Questions tab, question bubbles, answer snapshots; errors to transcript
This commit is contained in:
@@ -34,14 +34,13 @@ func (m *Manager) MergeAfterReview(ctx context.Context, task api.Task, user api.
|
||||
}
|
||||
}
|
||||
|
||||
snaps, err := m.store.ListSnapshots(ctx, task.Id)
|
||||
latest, err := m.store.LastSnapshotNot(ctx, task.Id, api.SnapshotTriggerAnswer)
|
||||
if errors.Is(err, store.ErrNotFound) {
|
||||
return api.Task{}, fmt.Errorf("%w: task %s has no snapshot under review", ErrConflict, task.Id)
|
||||
}
|
||||
if err != nil {
|
||||
return api.Task{}, err
|
||||
}
|
||||
if len(snaps) == 0 {
|
||||
return api.Task{}, fmt.Errorf("%w: task %s has no snapshot under review", ErrConflict, task.Id)
|
||||
}
|
||||
latest := snaps[len(snaps)-1]
|
||||
reviews, err := m.store.ListReviews(ctx, task.Id)
|
||||
if err != nil {
|
||||
return api.Task{}, err
|
||||
@@ -147,11 +146,11 @@ func (m *Manager) startMergeAfterReview(ctx context.Context, r api.Review, mar s
|
||||
if task.Discarding {
|
||||
return "the task is being discarded"
|
||||
}
|
||||
snaps, err := m.store.ListSnapshots(ctx, task.Id)
|
||||
latest, err := m.store.LastSnapshotNot(ctx, task.Id, api.SnapshotTriggerAnswer)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
if len(snaps) == 0 || snaps[len(snaps)-1].N != r.SnapshotN {
|
||||
if latest.N != r.SnapshotN {
|
||||
return "a newer snapshot was taken"
|
||||
}
|
||||
sess, found, err := m.liveSession(ctx, task.Id)
|
||||
|
||||
@@ -85,10 +85,8 @@ func (m *Manager) takeBounce(ctx context.Context, l *live, final string) (bool,
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, item := range open {
|
||||
if item.Kind == api.Question {
|
||||
return false, nil
|
||||
}
|
||||
if len(open) > 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
|
||||
+32
-43
@@ -127,7 +127,17 @@ func (m *Manager) ask(ctx context.Context, l *live, raw json.RawMessage) (string
|
||||
"attachments": attachments,
|
||||
}
|
||||
|
||||
err = m.store.CreateInboxItem(ctx, m.newItem(l, id, thread, api.Question, store.ToPayload(payload)))
|
||||
err = m.store.CreateInboxItem(ctx, api.InboxItem{
|
||||
Id: id,
|
||||
ProjectId: l.projectID,
|
||||
TaskId: l.taskID,
|
||||
AgentSessionId: l.id,
|
||||
ThreadId: thread,
|
||||
Payload: store.ToPayload(payload),
|
||||
State: api.Open,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
Responses: []api.InboxResponse{},
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -176,7 +186,7 @@ func (m *Manager) cancelQuestion(ctx context.Context, l *live, raw json.RawMessa
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if item.AgentSessionId != l.id || item.Kind != api.Question {
|
||||
if item.AgentSessionId != l.id {
|
||||
return "", fmt.Errorf("question_id %s is not a question you asked", args.QuestionID)
|
||||
}
|
||||
|
||||
@@ -251,35 +261,18 @@ func (m *Manager) validateAsk(ctx context.Context, l *live, args askArgs) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) fileError(l *live, msg string) {
|
||||
id := store.NewID()
|
||||
err := m.store.CreateInboxItem(context.Background(), m.newItem(l, id, id, api.SessionError, map[string]any{"error": msg}))
|
||||
func (m *Manager) recordError(l *live, msg string) {
|
||||
err := m.emit(context.Background(), l, "byre", "session.error", map[string]any{"error": msg})
|
||||
if err != nil {
|
||||
slog.Error("file session error", "session", l.id, "err", err)
|
||||
slog.Error("record session error", "session", l.id, "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) fileRateLimited(l *live, info map[string]any, failure string) {
|
||||
id := store.NewID()
|
||||
func (m *Manager) recordRateLimited(l *live, info map[string]any, failure string) {
|
||||
payload := map[string]any{"vendor": string(l.vendor), "rate_limit": info, "error": failure}
|
||||
err := m.store.CreateInboxItem(context.Background(), m.newItem(l, id, id, api.RateLimited, payload))
|
||||
err := m.emit(context.Background(), l, "byre", "session.rate_limited", payload)
|
||||
if err != nil {
|
||||
slog.Error("file rate limit", "session", l.id, "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) newItem(l *live, id, thread string, kind api.InboxItemKind, payload map[string]any) api.InboxItem {
|
||||
return api.InboxItem{
|
||||
Id: id,
|
||||
ProjectId: l.projectID,
|
||||
TaskId: l.taskID,
|
||||
AgentSessionId: l.id,
|
||||
ThreadId: thread,
|
||||
Kind: kind,
|
||||
Payload: payload,
|
||||
State: api.Open,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
Responses: []api.InboxResponse{},
|
||||
slog.Error("record rate limit", "session", l.id, "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,6 +319,12 @@ func (m *Manager) Deliver(ctx context.Context, sessionID string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
target, err := m.sessionTarget(ctx, sess, task)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
snapshotN := m.snapshotForAnswer(ctx, target, false)
|
||||
|
||||
images := []string{}
|
||||
for _, p := range pending {
|
||||
images = append(images, p.Response.Images...)
|
||||
@@ -350,8 +349,8 @@ func (m *Manager) Deliver(ctx context.Context, sessionID string) error {
|
||||
pid = l.sess.pid()
|
||||
exited = l.sess.exited()
|
||||
}
|
||||
slog.Info("deliver sent", "session", sessionID, "state", after.State, "pid", pid, "exited", exited, "closing", closing, "responses", ids)
|
||||
return m.store.MarkDelivered(ctx, ids)
|
||||
slog.Info("deliver sent", "session", sessionID, "state", after.State, "pid", pid, "exited", exited, "closing", closing, "responses", ids, "snapshot", snapshotN)
|
||||
return m.store.MarkDelivered(ctx, ids, snapshotN)
|
||||
}
|
||||
|
||||
type midTurn struct {
|
||||
@@ -454,7 +453,8 @@ func (m *Manager) responsesMidTurn(ctx context.Context, l *live) (string, []stri
|
||||
return "", nil
|
||||
}
|
||||
|
||||
err = m.store.MarkDelivered(ctx, ids)
|
||||
snapshotN := m.snapshotForAnswer(ctx, liveTarget(l), m.ownsTask(l.id))
|
||||
err = m.store.MarkDelivered(ctx, ids, snapshotN)
|
||||
if err != nil {
|
||||
slog.Error("mark responses delivered", "session", l.id, "err", err, "responses", ids)
|
||||
return "", nil
|
||||
@@ -465,7 +465,7 @@ func (m *Manager) responsesMidTurn(ctx context.Context, l *live) (string, []stri
|
||||
if err != nil {
|
||||
slog.Error("record mid-turn delivery", "session", l.id, "err", err)
|
||||
}
|
||||
slog.Info("deliver sent mid-turn", "session", l.id, "responses", ids)
|
||||
slog.Info("deliver sent mid-turn", "session", l.id, "responses", ids, "snapshot", snapshotN)
|
||||
return text, ids
|
||||
}
|
||||
|
||||
@@ -485,14 +485,7 @@ func deliveryMessage(pending []store.Pending) string {
|
||||
r := p.Response
|
||||
b.WriteString("\n")
|
||||
|
||||
switch p.Item.Kind {
|
||||
case api.Question:
|
||||
fmt.Fprintf(b, "Your question %s: %s\n", p.Item.Id, p.Item.Payload["question"])
|
||||
case api.SessionError:
|
||||
fmt.Fprintf(b, "Your error %s: %s\n", p.Item.Id, p.Item.Payload["error"])
|
||||
case api.RateLimited:
|
||||
fmt.Fprintf(b, "Your rate-limited turn %s: %s\n", p.Item.Id, p.Item.Payload["error"])
|
||||
}
|
||||
fmt.Fprintf(b, "Your question %s: %s\n", p.Item.Id, p.Item.Payload["question"])
|
||||
|
||||
switch r.Type {
|
||||
case api.Option:
|
||||
@@ -512,12 +505,8 @@ func deliveryMessage(pending []store.Pending) string {
|
||||
if r.Text != nil {
|
||||
text = *r.Text
|
||||
}
|
||||
if p.Item.Kind == api.Question {
|
||||
fmt.Fprintf(b, "%s answered (none of your options): %s\n", r.User, text)
|
||||
fmt.Fprintf(b, "If this asks you something back, answer by calling ask_human with thread_id %q.\n", p.Item.ThreadId)
|
||||
} else {
|
||||
fmt.Fprintf(b, "%s replied: %s\n", r.User, text)
|
||||
}
|
||||
fmt.Fprintf(b, "%s answered (none of your options): %s\n", r.User, text)
|
||||
fmt.Fprintf(b, "If this asks you something back, answer by calling ask_human with thread_id %q.\n", p.Item.ThreadId)
|
||||
}
|
||||
|
||||
if len(r.Images) > 0 {
|
||||
|
||||
+33
-34
@@ -15,13 +15,13 @@ import (
|
||||
)
|
||||
|
||||
const leadGuidance = `You are the human's lead agent in byre, shown in the left pane of byre's app. The human talks to you there, and you coordinate every task agent on their behalf. You don't do task work yourself: task agents work in their own worktrees, and you read, direct and report on them.
|
||||
- Signals: byre sends you, as messages from byre, what happens across tasks: questions and errors that task agents file, turns they finish with their final message, questions the human answered, tasks created, reviews started and finished, starting to merge, merged or discarded, and every change of a task's state, as "<task> state: <before> → <now>." listed first among what happened at the same moment. The states are running, idle, review_pending, reviewing, merging, discarding, merged, discarded and no_agent. A finished turn arrives with its state change: review_pending when byre is about to review the turn's work, reviewing while the review runs; neither is done, since the review can still find problems, so don't treat a task's work as finished until its state goes to idle. Several may arrive in one message, followed by the current task list (as list_tasks gives it) and what your right pane shows, so you rarely need to call list_tasks after a signal. The human doesn't see signals. Messages from the human arrive separately.
|
||||
- Signals: byre sends you, as messages from byre, what happens across tasks: questions that task agents ask, errors and rate limits their sessions hit, turns they finish with their final message, questions the human answered, tasks created, reviews started and finished, starting to merge, merged or discarded, and every change of a task's state, as "<task> state: <before> → <now>." listed first among what happened at the same moment. The states are running, idle, review_pending, reviewing, merging, discarding, merged, discarded and no_agent. A finished turn arrives with its state change: review_pending when byre is about to review the turn's work, reviewing while the review runs; neither is done, since the review can still find problems, so don't treat a task's work as finished until its state goes to idle. Several may arrive in one message, followed by the current task list (as list_tasks gives it) and what your right pane shows, so you rarely need to call list_tasks after a signal. The human doesn't see signals. Messages from the human arrive separately.
|
||||
- Don't respond to what the human just did. A signal about their own action (a question they answered, a task they created, merged, started merging or discarded) tells them nothing new: don't report, confirm or comment on it. Act on it only if it changes what you are doing, and then end the turn with one short line at most. When a batch of signals needs nothing from you to the human, make your final message exactly NO_REPLY and nothing else; byre folds that turn away so the human doesn't see it.
|
||||
- "Your right pane is free" means the human finished what was in the right pane. Show them the next thing that needs them, most urgent first (questions and errors, then finished turns, then tasks ready to merge), with one line saying what it is. If nothing needs them, show that project's project tab, then post a short status: one line per active task (what it's doing or waiting on), then up to three TODO items you'd start next (from list_tasks), each with a one-line reason. Write each item as a link to #/todo/<project_id>/<title, URL-encoded with parentheses as %28 and %29>, for example [Fix login redirect](#/todo/3f2a9c1b7d4e/Fix%20login%20redirect): byre draws it with a Start button the human can click, and once the task exists, its state. Start one with start_todo only when the human picks it. If that says nothing new since your last status, make your final message NO_REPLY.
|
||||
- "Your right pane is free" means the human finished what was in the right pane. Show them the next thing that needs them, most urgent first (questions, then errors on the task's transcript tab, then finished turns, then tasks ready to merge), with one line saying what it is. If nothing needs them, show that project's project tab, then post a short status: one line per active task (what it's doing or waiting on), then up to three TODO items you'd start next (from list_tasks), each with a one-line reason. Write each item as a link to #/todo/<project_id>/<title, URL-encoded with parentheses as %28 and %29>, for example [Fix login redirect](#/todo/3f2a9c1b7d4e/Fix%20login%20redirect): byre draws it with a Start button the human can click, and once the task exists, its state. Start one with start_todo only when the human picks it. If that says nothing new since your last status, make your final message NO_REPLY.
|
||||
- Whenever you suggest new work that isn't in TODO.md (a task you think is worth doing, an improvement to byre or to your own role), write it as a link to #/suggest/<project_id>/<title>/<brief>, both URL-encoded with parentheses as %28 and %29, for example [Lead tool for admin status](#/suggest/3f2a9c1b7d4e/Lead%20tool%20for%20admin%20status/Add%20a%20lead%20tool%20that%20reads%20%2Fapi%2Fadmin%2Fstatus%20...). The brief is the new task agent's whole first message, so make it a complete brief, as for create_task. byre draws the link with two buttons: Start creates the task with that title and brief at once, without you, and Discuss sends you a message asking to talk the suggestion over. Once an active task has that title, it shows the task's state instead. Don't ask whether to start a suggestion; the buttons do that.
|
||||
- Steering the right pane is a core part of your job, as important as what you write. The right pane shows one task, or a project with no task; point it with show (the task or project, the tabs to put first, the tab to select). By default, keep it on whatever you and the human are discussing, so they can see it while they read your reply; don't make them go looking for it. Call show in the same turn you bring something up:
|
||||
- Discussing, picking or starting TODO items, or a project's tasks as a whole: the project's project tab (show with project_id when no single task of that project is involved).
|
||||
- A question that needs the human: that task's inbox tab, with one line naming it and what you recommend.
|
||||
- A question that needs the human: that task's questions tab, with one line naming it and what you recommend.
|
||||
- A finished turn that needs the human, discussing a task's work, what its agent did or is doing, or whether it is ready to merge: its transcript tab, which ends with the agent's final message. A specific file in its worktree: its files tab.
|
||||
- The changes tab only when the human asks to see the diff; they rarely want it.
|
||||
- Show, don't tell. What the right pane shows, the human reads there: never repeat, quote or paraphrase a task agent's question, choices, context or final message in chat. Add only what the pane doesn't say, such as your recommendation and why, or how it connects to other work.
|
||||
@@ -34,7 +34,7 @@ const leadGuidance = `You are the human's lead agent in byre, shown in the left
|
||||
- You can create tasks, start TODO items, message, interrupt and compact task agents, and merge or discard tasks. Merge pushes to the default branch and Discard destroys work: do either only when the human asks for it.
|
||||
- Projects: when the human asks you to add a project, create it with create_project from its name and the path of its git repository on this machine.
|
||||
- Workflows: you manage the server's workflows with list_workflows, read_workflow, save_workflow and delete_workflow, and run one by giving its name to create_task or start_todo. Every stage of a workflow runs as its own task on the stage's model, once the stages it comes after have finished, so stages fan out (several stages after one) and fan in (one stage after several); a stage's agent calls finish_stage to hand its output to the stages after it, signals tell you when a stage starts and when the workflow finishes, and when the final stage finishes byre discards the run's other stage tasks, leaving the final one to merge. Whenever you show or propose a workflow, draw it as a Mermaid flowchart of its stage names only, with no models, for example a fenced mermaid block holding "flowchart LR", "Build --> Review", "Build --> Test", "Review --> Fix" and "Test --> Fix".
|
||||
- Whenever you name a task in a message, link it as a Markdown link to #/task/<task_id>, for example [Fix login redirect](#/task/da7e487305e4). byre draws it in that task's colour, and clicking it shows the task in the right pane. To open a specific tab, append it: #/task/<task_id>/<tab>. When you point the human at a question to answer, link to #/task/<task_id>/inbox; at a finished turn, to #/task/<task_id>/transcript.
|
||||
- Whenever you name a task in a message, link it as a Markdown link to #/task/<task_id>, for example [Fix login redirect](#/task/da7e487305e4). byre draws it in that task's colour, and clicking it shows the task in the right pane. To open a specific tab, append it: #/task/<task_id>/<tab>. When you point the human at a question to answer, link to #/task/<task_id>/questions; at a finished turn, to #/task/<task_id>/transcript.
|
||||
- Keep messages short; the human reads them in half the screen. Put long detail in collapsed sections: a line <details><summary>Title</summary>, the Markdown content, then a line </details>.
|
||||
- You are long-running. Your context window is large. byre sends you a signal once your context passes half of its window; then call compact_self at a logical point (a piece of work wrapped up, a topic closed), and not before; when the turn ends, byre replaces you with a fresh session that starts from your handoff.
|
||||
- Don't commit, push, or touch git branches yourself.`
|
||||
@@ -326,6 +326,10 @@ func (m *Manager) Observe(events []api.Event) {
|
||||
if ev.TaskId == nil || !humanActor(ev.Actor) {
|
||||
continue
|
||||
}
|
||||
case "session.error", "session.rate_limited":
|
||||
if ev.TaskId == nil {
|
||||
continue
|
||||
}
|
||||
default:
|
||||
continue
|
||||
}
|
||||
@@ -473,6 +477,12 @@ func (m *Manager) signalText(ctx context.Context, ev api.Event) (string, error)
|
||||
}
|
||||
return m.itemText(ctx, item), nil
|
||||
|
||||
case "session.error":
|
||||
return fmt.Sprintf("%s hit an error: %v", m.taskLabel(ctx, deref(ev.TaskId)), ev.Payload["error"]), nil
|
||||
|
||||
case "session.rate_limited":
|
||||
return fmt.Sprintf("%s was rate limited: %v", m.taskLabel(ctx, deref(ev.TaskId)), ev.Payload["error"]), nil
|
||||
|
||||
case "task.created":
|
||||
task := api.Task{}
|
||||
err := remarshal(ev.Payload, &task)
|
||||
@@ -547,34 +557,26 @@ func (m *Manager) signalText(ctx context.Context, ev api.Event) (string, error)
|
||||
func (m *Manager) itemText(ctx context.Context, item api.InboxItem) string {
|
||||
label := m.taskLabel(ctx, item.TaskId)
|
||||
p := item.Payload
|
||||
switch item.Kind {
|
||||
case api.Question:
|
||||
b := &strings.Builder{}
|
||||
fmt.Fprintf(b, "%s asked question %s: %v\n", label, item.Id, p["question"])
|
||||
recommended := map[string]bool{}
|
||||
for _, r := range anyStrings(p["recommended"]) {
|
||||
recommended[r] = true
|
||||
}
|
||||
kind := "pick one"
|
||||
if p["multiple"] == true {
|
||||
kind = "pick any"
|
||||
}
|
||||
fmt.Fprintf(b, "Choices (%s):\n", kind)
|
||||
for _, o := range anyStrings(p["options"]) {
|
||||
mark := ""
|
||||
if recommended[o] {
|
||||
mark = " (recommended)"
|
||||
}
|
||||
fmt.Fprintf(b, "- %s%s\n", clip(o, 300), mark)
|
||||
}
|
||||
fmt.Fprintf(b, "Blocked on: %v\nThe full context is in read_inbox.", p["why_blocked"])
|
||||
return b.String()
|
||||
case api.SessionError:
|
||||
return fmt.Sprintf("%s hit an error (item %s): %v", label, item.Id, p["error"])
|
||||
case api.RateLimited:
|
||||
return fmt.Sprintf("%s was rate limited (item %s): %v", label, item.Id, p["error"])
|
||||
b := &strings.Builder{}
|
||||
fmt.Fprintf(b, "%s asked question %s: %v\n", label, item.Id, p["question"])
|
||||
recommended := map[string]bool{}
|
||||
for _, r := range anyStrings(p["recommended"]) {
|
||||
recommended[r] = true
|
||||
}
|
||||
return ""
|
||||
kind := "pick one"
|
||||
if p["multiple"] == true {
|
||||
kind = "pick any"
|
||||
}
|
||||
fmt.Fprintf(b, "Choices (%s):\n", kind)
|
||||
for _, o := range anyStrings(p["options"]) {
|
||||
mark := ""
|
||||
if recommended[o] {
|
||||
mark = " (recommended)"
|
||||
}
|
||||
fmt.Fprintf(b, "- %s%s\n", clip(o, 300), mark)
|
||||
}
|
||||
fmt.Fprintf(b, "Blocked on: %v\nThe full context is in read_inbox.", p["why_blocked"])
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (m *Manager) answeredText(ctx context.Context, item api.InboxItem) string {
|
||||
@@ -594,9 +596,6 @@ func (m *Manager) answeredText(ctx context.Context, item api.InboxItem) string {
|
||||
if r.Text != nil && strings.TrimSpace(*r.Text) != "" {
|
||||
answer = strings.TrimSpace(answer + " " + *r.Text)
|
||||
}
|
||||
if item.Kind != api.Question {
|
||||
return fmt.Sprintf("%s: %s answered %s %s: %s", m.taskLabel(ctx, item.TaskId), r.User, item.Kind, item.Id, clip(answer, 600))
|
||||
}
|
||||
recommended := strings.Join(anyStrings(item.Payload["recommended"]), "; ")
|
||||
return fmt.Sprintf("%s: %s answered question %s %q: %s\nThe agent recommended: %s", m.taskLabel(ctx, item.TaskId), r.User, item.Id, clip(fmt.Sprint(item.Payload["question"]), 300), clip(answer, 600), clip(recommended, 600))
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
|
||||
|
||||
return append([]mcp.Tool{
|
||||
tool("list_tasks",
|
||||
"List every project and its active tasks (id, title, worktree path, the agent's state and model, and open inbox items), "+
|
||||
"List every project and its active tasks (id, title, worktree path, the agent's state and model, and open questions), "+
|
||||
"and the titles of its TODO.md items on the default branch that no active task was started from.",
|
||||
`{"type": "object", "properties": {}}`,
|
||||
func(ctx context.Context, user api.User, raw json.RawMessage) (string, error) {
|
||||
@@ -44,7 +44,7 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
|
||||
}),
|
||||
|
||||
tool("read_transcript",
|
||||
"Read a task's transcript: messages, tool calls (briefly), tool results (cut short), turn ends and inbox filings, each with its event seq. "+
|
||||
"Read a task's transcript: messages, tool calls (briefly), tool results (cut short), turn ends, questions asked, errors and rate limits, each with its event seq. "+
|
||||
"Without after_seq it returns the last limit events; with it, the events after that seq.",
|
||||
`{"type": "object", "properties": {
|
||||
"task_id": {"type": "string"},
|
||||
@@ -77,7 +77,7 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
|
||||
}),
|
||||
|
||||
tool("read_inbox",
|
||||
"Read open inbox items as JSON, with each question's full context, choices and responses. Give task_id for one task's items.",
|
||||
"Read open questions as JSON, with each one's full context, choices and responses. Give task_id for one task's questions.",
|
||||
`{"type": "object", "properties": {"task_id": {"type": "string"}}}`,
|
||||
func(ctx context.Context, user api.User, raw json.RawMessage) (string, error) {
|
||||
args := struct {
|
||||
@@ -110,12 +110,12 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
|
||||
}),
|
||||
|
||||
tool("answer_question",
|
||||
"Respond to an open inbox item on the human's behalf. Only when the answer is clear or the human told you it. "+
|
||||
"Answer an open question on the human's behalf. Only when the answer is clear or the human told you it. "+
|
||||
"type option: options holds the chosen choices' exact text (one for pick-one; pick-any may add text). "+
|
||||
"type other: free text to a question or an error. type dismiss: clears an error.",
|
||||
"type other: free text.",
|
||||
`{"type": "object", "properties": {
|
||||
"item_id": {"type": "string"},
|
||||
"type": {"type": "string", "enum": ["option", "other", "dismiss"]},
|
||||
"type": {"type": "string", "enum": ["option", "other"]},
|
||||
"options": {"type": "array", "items": {"type": "string"}},
|
||||
"text": {"type": "string"}
|
||||
}, "required": ["item_id", "type"]}`,
|
||||
@@ -388,7 +388,7 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
|
||||
"Merge a task as the human: its agent merges the default branch in, then byre squashes it into one commit, pushes it to origin and closes the task. "+
|
||||
"While another task in the project is merging, byre holds the merge and starts it when that one is done. "+
|
||||
"For a subtask, target parent instead asks its parent task's agent to merge it into the parent's branch, and the subtask closes once the parent has. "+
|
||||
"Refused for a task with active subtasks. Only when the human asks. You get a signal when it is merged; failures are filed in the task's inbox.",
|
||||
"Refused for a task with active subtasks. Only when the human asks. You get a signal when it is merged; failures show as errors in the task's transcript, and you get a signal for each.",
|
||||
`{"type": "object", "properties": {
|
||||
"task_id": {"type": "string"},
|
||||
"target": {"type": "string", "enum": ["main", "parent"], "description": "Default main."}
|
||||
@@ -458,18 +458,18 @@ 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: tabs are the tabs to put first, in order (the rest follow), and tab is the one to select. "+
|
||||
"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 (a shell in the task's worktree), inbox (the task's open items), reviews (the task's reviews by reviewer agents), 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. "+
|
||||
"Tabs: transcript, board (a team task's board: its agents' posts, the human's and yours), changes, files, terminal (a shell in the task's worktree), questions (the task's oldest open question), reviews (the task's reviews by reviewer agents), 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, only the tab order changes and you are told so, even while the human is working in the pane. "+
|
||||
"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 an inbox tab with nothing left), "+
|
||||
"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 a questions tab with nothing left open),"+
|
||||
"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.",
|
||||
`{"type": "object", "properties": {
|
||||
"task_id": {"type": "string"},
|
||||
"project_id": {"type": "string", "description": "Ignored when task_id is given."},
|
||||
"tabs": {"type": "array", "items": {"type": "string", "enum": ["transcript", "board", "changes", "files", "terminal", "inbox", "reviews", "workflow", "project"]}},
|
||||
"tab": {"type": "string", "enum": ["transcript", "board", "changes", "files", "terminal", "inbox", "reviews", "workflow", "project"]}
|
||||
"tabs": {"type": "array", "items": {"type": "string", "enum": ["transcript", "board", "changes", "files", "terminal", "questions", "reviews", "workflow", "project"]}},
|
||||
"tab": {"type": "string", "enum": ["transcript", "board", "changes", "files", "terminal", "questions", "reviews", "workflow", "project"]}
|
||||
}, "required": ["tabs", "tab"]}`,
|
||||
func(ctx context.Context, user api.User, raw json.RawMessage) (string, error) {
|
||||
f := api.Focus{}
|
||||
@@ -640,7 +640,7 @@ func sameView(a, b api.Focus) bool {
|
||||
return deref(a.ProjectId) == deref(b.ProjectId)
|
||||
}
|
||||
|
||||
const inboxEmptied = "has nothing left in its inbox"
|
||||
const inboxEmptied = "has no open questions left"
|
||||
|
||||
func (m *Manager) paneFinished(ctx context.Context, f api.Focus) (string, error) {
|
||||
if f.TaskId == nil {
|
||||
@@ -656,7 +656,7 @@ func (m *Manager) paneFinished(ctx context.Context, f api.Focus) (string, error)
|
||||
if task.Merging {
|
||||
return "is merging", nil
|
||||
}
|
||||
if f.Tab != api.TabInbox {
|
||||
if f.Tab != api.TabQuestions {
|
||||
return "", nil
|
||||
}
|
||||
items, err := m.store.ListInbox(ctx, store.InboxFilter{State: api.Open, TaskID: task.Id})
|
||||
@@ -883,7 +883,7 @@ func (m *Manager) listTasksText(ctx context.Context) (string, error) {
|
||||
open++
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(b, "- %s %q: %s; inbox %d open; worktree %s", t.Id, t.Title, agent, open, t.WorktreePath)
|
||||
fmt.Fprintf(b, "- %s %q: %s; %d open questions; worktree %s", t.Id, t.Title, agent, open, t.WorktreePath)
|
||||
if t.TodoItem != nil {
|
||||
fmt.Fprintf(b, "; from TODO item %q", *t.TodoItem)
|
||||
}
|
||||
@@ -1023,7 +1023,11 @@ func transcriptLine(ev api.Event, root string) string {
|
||||
}
|
||||
return "turn ended"
|
||||
case "inbox.created":
|
||||
return fmt.Sprintf("filed %s %s", text("kind"), text("id"))
|
||||
return fmt.Sprintf("asked question %s", text("id"))
|
||||
case "session.error":
|
||||
return "error: " + clip(text("error"), 300)
|
||||
case "session.rate_limited":
|
||||
return "rate limited: " + clip(text("error"), 300)
|
||||
case "session.created":
|
||||
return fmt.Sprintf("session started by %s", ev.Actor)
|
||||
case "session.state":
|
||||
|
||||
@@ -889,7 +889,7 @@ func (m *Manager) pump(l *live) {
|
||||
if m.leadsTask(ctx, l.taskID, l.id) {
|
||||
m.abandonMerge(l.taskID, l.projectID)
|
||||
}
|
||||
m.fileError(l, "The agent process exited mid-turn. Send a message to resume it.")
|
||||
m.recordError(l, "The agent process exited mid-turn. Send a message to resume it.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1104,7 +1104,7 @@ func (m *Manager) turnEnded(ctx context.Context, l *live, res endResult) error {
|
||||
sha, err := git.CommitAll(l.dir, commitMessage(res), l.gitName, l.gitEmail)
|
||||
if err != nil {
|
||||
slog.Error("commit turn", "session", l.id, "err", err)
|
||||
m.fileError(l, fmt.Sprintf("byre couldn't commit the turn's work, so the turn counts as unfinished: %v", err))
|
||||
m.recordError(l, fmt.Sprintf("byre couldn't commit the turn's work, so the turn counts as unfinished: %v", err))
|
||||
finished = false
|
||||
if owner {
|
||||
err = git.AbortMerge(l.dir)
|
||||
@@ -1152,9 +1152,9 @@ func (m *Manager) turnEnded(ctx context.Context, l *live, res endResult) error {
|
||||
switch {
|
||||
case !res.isError || interrupted:
|
||||
case rateLimited != nil:
|
||||
m.fileRateLimited(l, rateLimited, failure)
|
||||
m.recordRateLimited(l, rateLimited, failure)
|
||||
default:
|
||||
m.fileError(l, failure)
|
||||
m.recordError(l, failure)
|
||||
}
|
||||
|
||||
stageFinished := false
|
||||
@@ -1217,7 +1217,7 @@ func (m *Manager) turnEnded(ctx context.Context, l *live, res endResult) error {
|
||||
case mergeBy != "":
|
||||
go m.releaseMerge(l.projectID, l.taskID)
|
||||
if !res.isError || interrupted {
|
||||
m.fileError(l, "The Merge turn ended unfinished (interrupted, or with no final message), so byre didn't squash or push the task. Merge again to retry.")
|
||||
m.recordError(l, "The Merge turn ended unfinished (interrupted, or with no final message), so byre didn't squash or push the task. Merge again to retry.")
|
||||
}
|
||||
default:
|
||||
go m.nextMerge(l.projectID)
|
||||
|
||||
@@ -392,7 +392,7 @@ func (m *Manager) fileTaskError(ctx context.Context, task api.Task, sessions []a
|
||||
return
|
||||
}
|
||||
last := sessions[len(sessions)-1]
|
||||
m.fileError(&live{id: last.Id, taskID: task.Id, projectID: task.ProjectId}, msg)
|
||||
m.recordError(&live{id: last.Id, taskID: task.Id, projectID: task.ProjectId}, msg)
|
||||
}
|
||||
|
||||
func (m *Manager) takeMerge(taskID string) string {
|
||||
@@ -416,14 +416,14 @@ func (m *Manager) finishMerge(l *live, login string) {
|
||||
slog.Error("finish merge", "task", l.taskID, "err", err)
|
||||
unfinished := &unfinishedMergeError{}
|
||||
if errors.As(err, &unfinished) {
|
||||
m.fileError(l, "Merging the task failed: "+err.Error()+".")
|
||||
m.recordError(l, "Merging the task failed: "+err.Error()+".")
|
||||
return
|
||||
}
|
||||
cerr := m.store.ClearFinalizing(ctx, l.taskID)
|
||||
if cerr != nil {
|
||||
slog.Error("clear merge finalizing", "task", l.taskID, "err", cerr)
|
||||
}
|
||||
m.fileError(l, "Merging the task failed: "+err.Error())
|
||||
m.recordError(l, "Merging the task failed: "+err.Error())
|
||||
err = m.Deliver(ctx, l.id)
|
||||
if err != nil {
|
||||
slog.Error("deliver inbox responses", "session", l.id, "err", err)
|
||||
|
||||
@@ -69,15 +69,9 @@ func (m *Manager) mergeNote(ctx context.Context, task api.Task, login string) (s
|
||||
}
|
||||
}
|
||||
|
||||
decisions := []api.InboxItem{}
|
||||
for _, item := range answered {
|
||||
if item.Kind == api.Question {
|
||||
decisions = append(decisions, item)
|
||||
}
|
||||
}
|
||||
if len(decisions) > 0 {
|
||||
if len(answered) > 0 {
|
||||
b.WriteString("\n## Decisions\n")
|
||||
for _, item := range decisions {
|
||||
for _, item := range answered {
|
||||
fmt.Fprintf(b, "\n### %s\n", item.Payload["question"])
|
||||
background, _ := item.Payload["context"].(string)
|
||||
if strings.TrimSpace(background) != "" {
|
||||
|
||||
@@ -108,16 +108,12 @@ func CheckResponse(item api.InboxItem, c api.InboxResponseCreate) (api.InboxStat
|
||||
text = strings.TrimSpace(*c.Text)
|
||||
}
|
||||
images := c.Images != nil && len(*c.Images) > 0
|
||||
question := item.Kind == api.Question
|
||||
bad := func(format string, args ...any) (api.InboxState, error) {
|
||||
return "", fmt.Errorf("%w: item %s: "+format, append([]any{ErrInvalid, item.Id}, args...)...)
|
||||
}
|
||||
|
||||
switch c.Type {
|
||||
case api.Option:
|
||||
if !question {
|
||||
return bad("only questions have options")
|
||||
}
|
||||
if c.Options == nil || len(*c.Options) == 0 {
|
||||
return bad("option needs the chosen options")
|
||||
}
|
||||
@@ -144,15 +140,6 @@ func CheckResponse(item api.InboxItem, c api.InboxResponseCreate) (api.InboxStat
|
||||
return bad("other needs text or images")
|
||||
}
|
||||
return api.Answered, nil
|
||||
|
||||
case api.Dismiss:
|
||||
if question {
|
||||
return bad("questions need an option or other, not a dismissal")
|
||||
}
|
||||
if images {
|
||||
return bad("a dismissal takes no images")
|
||||
}
|
||||
return api.Dismissed, nil
|
||||
}
|
||||
|
||||
return bad("unknown response type %q", c.Type)
|
||||
|
||||
@@ -145,7 +145,11 @@ func (m *Manager) takeSnapshot(ctx context.Context, t snapTarget, trigger api.Sn
|
||||
if err != nil && !errors.Is(err, store.ErrNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
if err == nil && last.TreeSha == tree && !force {
|
||||
reviewed, err := m.store.LastSnapshotNot(ctx, t.taskID, api.SnapshotTriggerAnswer)
|
||||
if err != nil && !errors.Is(err, store.ErrNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
if err == nil && reviewed.TreeSha == tree && !force {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -179,7 +183,7 @@ func (m *Manager) takeSnapshot(ctx context.Context, t snapTarget, trigger api.Sn
|
||||
}
|
||||
|
||||
func (m *Manager) RequestSnapshot(ctx context.Context, taskID string) error {
|
||||
task, project, err := m.activeTask(ctx, taskID)
|
||||
task, _, err := m.activeTask(ctx, taskID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -204,8 +208,7 @@ func (m *Manager) RequestSnapshot(ctx context.Context, taskID string) error {
|
||||
if len(sessions) == 0 {
|
||||
return fmt.Errorf("%w: task %s has no agent session to attribute a snapshot to", ErrConflict, task.Id)
|
||||
}
|
||||
sess := sessions[len(sessions)-1]
|
||||
creator, err := m.store.GetUser(ctx, sess.CreatedBy)
|
||||
t, err := m.sessionTarget(ctx, sessions[len(sessions)-1], task)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -213,11 +216,44 @@ func (m *Manager) RequestSnapshot(ctx context.Context, taskID string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t := snapTarget{taskID: task.Id, projectID: project.Id, sessionID: sess.Id, dir: task.WorktreePath, gitName: creator.GitName, gitEmail: creator.GitEmail}
|
||||
m.snapshotSoon(t, api.SnapshotTriggerRequested, 0, true, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) sessionTarget(ctx context.Context, sess api.AgentSession, task api.Task) (snapTarget, error) {
|
||||
creator, err := m.store.GetUser(ctx, sess.CreatedBy)
|
||||
if err != nil {
|
||||
return snapTarget{}, err
|
||||
}
|
||||
return snapTarget{taskID: task.Id, projectID: task.ProjectId, sessionID: sess.Id, dir: task.WorktreePath, gitName: creator.GitName, gitEmail: creator.GitEmail}, nil
|
||||
}
|
||||
|
||||
func (m *Manager) snapshotForAnswer(ctx context.Context, t snapTarget, held bool) int {
|
||||
if !held {
|
||||
unlock := m.lockTask(t.taskID)
|
||||
defer unlock()
|
||||
}
|
||||
m.snapMu.Lock()
|
||||
st := m.snapStateLocked(t.taskID)
|
||||
m.snapMu.Unlock()
|
||||
st.mu.Lock()
|
||||
defer st.mu.Unlock()
|
||||
m.snapMu.Lock()
|
||||
closed := st.closed
|
||||
m.snapMu.Unlock()
|
||||
if closed {
|
||||
return 0
|
||||
}
|
||||
|
||||
snap, err := m.takeSnapshot(ctx, t, api.SnapshotTriggerAnswer, 0, true)
|
||||
if err != nil {
|
||||
slog.Error("take snapshot", "task", t.taskID, "trigger", api.SnapshotTriggerAnswer, "err", err)
|
||||
m.recordError(&live{id: t.sessionID, taskID: t.taskID, projectID: t.projectID}, fmt.Sprintf("byre couldn't snapshot the worktree before handing over an answer, so the answer went to the agent without one: %v", err))
|
||||
return 0
|
||||
}
|
||||
return snap.N
|
||||
}
|
||||
|
||||
func (m *Manager) takeSnapshotTool(l *live) mcp.Tool {
|
||||
return mcp.Tool{
|
||||
Name: "take_snapshot",
|
||||
|
||||
@@ -111,7 +111,7 @@ func (m *Manager) subtaskTools(l *live) []mcp.Tool {
|
||||
}),
|
||||
|
||||
tool("read_subtask",
|
||||
"Read a subtask's transcript: messages, tool calls (briefly), tool results (cut short), turn ends and inbox filings, each with its event seq. "+
|
||||
"Read a subtask's transcript: messages, tool calls (briefly), tool results (cut short), turn ends, questions asked, errors and rate limits, each with its event seq. "+
|
||||
"Without after_seq it returns the last limit events; with it, the events after that seq.",
|
||||
`{"type": "object", "properties": {
|
||||
"task_id": {"type": "string"},
|
||||
|
||||
@@ -315,7 +315,7 @@ func (m *Manager) advanceStage(l *live) {
|
||||
_, err := m.nextStage(ctx, l.id)
|
||||
if err != nil {
|
||||
slog.Error("advance workflow stage", "session", l.id, "err", err)
|
||||
m.fileError(l, fmt.Sprintf("The workflow didn't move on from this stage: %v. byre tries again when it next starts.", err))
|
||||
m.recordError(l, fmt.Sprintf("The workflow didn't move on from this stage: %v. byre tries again when it next starts.", err))
|
||||
}
|
||||
m.afterTurn(ctx, l)
|
||||
}
|
||||
|
||||
+277
-297
@@ -231,39 +231,15 @@ func (e FindingState) Valid() bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Defines values for InboxItemKind.
|
||||
const (
|
||||
Question InboxItemKind = "question"
|
||||
RateLimited InboxItemKind = "rate_limited"
|
||||
SessionError InboxItemKind = "session_error"
|
||||
)
|
||||
|
||||
// Valid indicates whether the value is a known member of the InboxItemKind enum.
|
||||
func (e InboxItemKind) Valid() bool {
|
||||
switch e {
|
||||
case Question:
|
||||
return true
|
||||
case RateLimited:
|
||||
return true
|
||||
case SessionError:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Defines values for InboxResponseType.
|
||||
const (
|
||||
Dismiss InboxResponseType = "dismiss"
|
||||
Option InboxResponseType = "option"
|
||||
Other InboxResponseType = "other"
|
||||
Option InboxResponseType = "option"
|
||||
Other InboxResponseType = "other"
|
||||
)
|
||||
|
||||
// Valid indicates whether the value is a known member of the InboxResponseType enum.
|
||||
func (e InboxResponseType) Valid() bool {
|
||||
switch e {
|
||||
case Dismiss:
|
||||
return true
|
||||
case Option:
|
||||
return true
|
||||
case Other:
|
||||
@@ -323,6 +299,7 @@ func (e ReviewState) Valid() bool {
|
||||
|
||||
// Defines values for SnapshotTrigger.
|
||||
const (
|
||||
SnapshotTriggerAnswer SnapshotTrigger = "answer"
|
||||
SnapshotTriggerAskHuman SnapshotTrigger = "ask_human"
|
||||
SnapshotTriggerMessage SnapshotTrigger = "message"
|
||||
SnapshotTriggerRequested SnapshotTrigger = "requested"
|
||||
@@ -334,6 +311,8 @@ const (
|
||||
// Valid indicates whether the value is a known member of the SnapshotTrigger enum.
|
||||
func (e SnapshotTrigger) Valid() bool {
|
||||
switch e {
|
||||
case SnapshotTriggerAnswer:
|
||||
return true
|
||||
case SnapshotTriggerAskHuman:
|
||||
return true
|
||||
case SnapshotTriggerMessage:
|
||||
@@ -464,8 +443,8 @@ const (
|
||||
TabBoard TaskTab = "board"
|
||||
TabChanges TaskTab = "changes"
|
||||
TabFiles TaskTab = "files"
|
||||
TabInbox TaskTab = "inbox"
|
||||
TabProject TaskTab = "project"
|
||||
TabQuestions TaskTab = "questions"
|
||||
TabReviews TaskTab = "reviews"
|
||||
TabTerminal TaskTab = "terminal"
|
||||
TabTranscript TaskTab = "transcript"
|
||||
@@ -481,10 +460,10 @@ func (e TaskTab) Valid() bool {
|
||||
return true
|
||||
case TabFiles:
|
||||
return true
|
||||
case TabInbox:
|
||||
return true
|
||||
case TabProject:
|
||||
return true
|
||||
case TabQuestions:
|
||||
return true
|
||||
case TabReviews:
|
||||
return true
|
||||
case TabTerminal:
|
||||
@@ -866,14 +845,13 @@ type Focus struct {
|
||||
TaskId *string `json:"task_id,omitempty"`
|
||||
}
|
||||
|
||||
// InboxItem defines model for InboxItem.
|
||||
// InboxItem A question an agent asked the human with ask_human.
|
||||
type InboxItem struct {
|
||||
AgentSessionId string `json:"agent_session_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Id string `json:"id"`
|
||||
Kind InboxItemKind `json:"kind"`
|
||||
AgentSessionId string `json:"agent_session_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Id string `json:"id"`
|
||||
|
||||
// Payload question: context (Markdown with the choices inline as `- ( ) text` / `- (*) text` pick-one or `- [ ] text` / `- [x] text` pick-any list items), question, why_blocked, options (each choice's text, in order), multiple (true for pick-any), recommended (the marked choices' text), attachments. session_error: error. rate_limited: vendor, rate_limit (the vendor's rate-limit status), error.
|
||||
// Payload context (Markdown with the choices inline as `- ( ) text` / `- (*) text` pick-one or `- [ ] text` / `- [x] text` pick-any list items), question, why_blocked, options (each choice's text, in order), multiple (true for pick-any), recommended (the marked choices' text), attachments.
|
||||
Payload map[string]interface{} `json:"payload"`
|
||||
ProjectId string `json:"project_id"`
|
||||
ResolvedAt *time.Time `json:"resolved_at,omitempty"`
|
||||
@@ -884,9 +862,6 @@ type InboxItem struct {
|
||||
ThreadId string `json:"thread_id"`
|
||||
}
|
||||
|
||||
// InboxItemKind defines model for InboxItem.Kind.
|
||||
type InboxItemKind string
|
||||
|
||||
// InboxRespond defines model for InboxRespond.
|
||||
type InboxRespond struct {
|
||||
Responses []InboxResponseCreate `json:"responses"`
|
||||
@@ -900,12 +875,15 @@ type InboxResponse struct {
|
||||
Id string `json:"id"`
|
||||
|
||||
// Images Blob ids sent to the agent as images alongside the response.
|
||||
Images []string `json:"images"`
|
||||
ItemId string `json:"item_id"`
|
||||
Options *[]string `json:"options,omitempty"`
|
||||
Text *string `json:"text,omitempty"`
|
||||
Type InboxResponseType `json:"type"`
|
||||
User string `json:"user"`
|
||||
Images []string `json:"images"`
|
||||
ItemId string `json:"item_id"`
|
||||
Options *[]string `json:"options,omitempty"`
|
||||
|
||||
// SnapshotN The task's snapshot of the worktree as it stood just before the response was handed to the agent; absent until delivered, and when no snapshot could be taken.
|
||||
SnapshotN *int `json:"snapshot_n,omitempty"`
|
||||
Text *string `json:"text,omitempty"`
|
||||
Type InboxResponseType `json:"type"`
|
||||
User string `json:"user"`
|
||||
}
|
||||
|
||||
// InboxResponseCreate defines model for InboxResponseCreate.
|
||||
@@ -953,15 +931,15 @@ type MessageCreate struct {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
// NotificationPrefs Which new inbox items and finished turns notify this user in their open byre pages.
|
||||
// NotificationPrefs Which new questions, finished turns, errors and rate limits notify this user in their open byre pages.
|
||||
type NotificationPrefs struct {
|
||||
// Errors session_error items.
|
||||
// Errors session.error events on tasks.
|
||||
Errors bool `json:"errors"`
|
||||
|
||||
// Questions Questions. On by default.
|
||||
Questions bool `json:"questions"`
|
||||
|
||||
// RateLimits rate_limited items.
|
||||
// RateLimits session.rate_limited events on tasks.
|
||||
RateLimits bool `json:"rate_limits"`
|
||||
|
||||
// Reports Task turns that end with a summary (turn.ended with summary: true).
|
||||
@@ -1094,11 +1072,11 @@ type Snapshot struct {
|
||||
TaskId string `json:"task_id"`
|
||||
TreeSha string `json:"tree_sha"`
|
||||
|
||||
// Trigger turn_end: after byre's end-of-turn commit. requested: a task's agent or the lead asked for it with take_snapshot. message (the agent wrote text after one or more tool calls), tool_call, ask_human and timer appear only on snapshots taken by earlier builds.
|
||||
// Trigger turn_end: after byre's end-of-turn commit. requested: a task's agent or the lead asked for it with take_snapshot. answer: just before answers from the human were handed to the agent. message (the agent wrote text after one or more tool calls), tool_call, ask_human and timer appear only on snapshots taken by earlier builds.
|
||||
Trigger SnapshotTrigger `json:"trigger"`
|
||||
}
|
||||
|
||||
// SnapshotTrigger turn_end: after byre's end-of-turn commit. requested: a task's agent or the lead asked for it with take_snapshot. message (the agent wrote text after one or more tool calls), tool_call, ask_human and timer appear only on snapshots taken by earlier builds.
|
||||
// SnapshotTrigger turn_end: after byre's end-of-turn commit. requested: a task's agent or the lead asked for it with take_snapshot. answer: just before answers from the human were handed to the agent. message (the agent wrote text after one or more tool calls), tool_call, ask_human and timer appear only on snapshots taken by earlier builds.
|
||||
type SnapshotTrigger string
|
||||
|
||||
// Stage defines model for Stage.
|
||||
@@ -1384,7 +1362,7 @@ type User struct {
|
||||
GitName string `json:"git_name"`
|
||||
Login string `json:"login"`
|
||||
|
||||
// NotificationPrefs Which new inbox items and finished turns notify this user in their open byre pages.
|
||||
// NotificationPrefs Which new questions, finished turns, errors and rate limits notify this user in their open byre pages.
|
||||
NotificationPrefs NotificationPrefs `json:"notification_prefs"`
|
||||
}
|
||||
|
||||
@@ -3803,253 +3781,255 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H
|
||||
// const string: with thousands of chunks the chained `+` fold is several
|
||||
// times slower for the Go compiler than parsing a slice literal.
|
||||
var swaggerSpec = []string{
|
||||
"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",
|
||||
"ewA=",
|
||||
}
|
||||
|
||||
// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
|
||||
|
||||
+24
-26
@@ -12,14 +12,6 @@ import (
|
||||
"g.fc.run/misc/byre/internal/api"
|
||||
)
|
||||
|
||||
func DeliverableResponse(t api.InboxResponseType) bool {
|
||||
switch t {
|
||||
case api.Option, api.Other:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Store) CreateInboxItem(ctx context.Context, item api.InboxItem) error {
|
||||
return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
|
||||
payload, err := json.Marshal(item.Payload)
|
||||
@@ -28,9 +20,9 @@ func (s *Store) CreateInboxItem(ctx context.Context, item api.InboxItem) error {
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx, `
|
||||
INSERT INTO inbox_items (id, project_id, task_id, agent_session_id, thread_id, kind, payload, state, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`, item.Id, item.ProjectId, item.TaskId, item.AgentSessionId, item.ThreadId, string(item.Kind),
|
||||
INSERT INTO inbox_items (id, project_id, task_id, agent_session_id, thread_id, payload, state, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`, item.Id, item.ProjectId, item.TaskId, item.AgentSessionId, item.ThreadId,
|
||||
string(payload), string(item.State), formatTime(item.CreatedAt))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -220,10 +212,9 @@ func (s *Store) AwaitingHuman(ctx context.Context, sessionID string) (int, error
|
||||
n := 0
|
||||
err := s.db.QueryRowContext(ctx, `
|
||||
SELECT COUNT(*) FROM inbox_items i
|
||||
WHERE i.agent_session_id = ? AND i.kind = ? AND i.state = ?
|
||||
AND NOT EXISTS (SELECT 1 FROM inbox_responses r WHERE r.item_id = i.id AND r.type IN (?, ?))
|
||||
`, sessionID, string(api.Question), string(api.Open),
|
||||
string(api.Option), string(api.Other)).Scan(&n)
|
||||
WHERE i.agent_session_id = ? AND i.state = ?
|
||||
AND NOT EXISTS (SELECT 1 FROM inbox_responses r WHERE r.item_id = i.id)
|
||||
`, sessionID, string(api.Open)).Scan(&n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
@@ -235,9 +226,9 @@ type Pending struct {
|
||||
func (s *Store) Undelivered(ctx context.Context, sessionID string) ([]Pending, error) {
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
SELECT r.id, r.item_id FROM inbox_responses r JOIN inbox_items i ON i.id = r.item_id
|
||||
WHERE i.agent_session_id = ? AND r.delivered_at IS NULL AND r.type IN (?, ?)
|
||||
WHERE i.agent_session_id = ? AND r.delivered_at IS NULL
|
||||
ORDER BY r.created_at
|
||||
`, sessionID, string(api.Option), string(api.Other))
|
||||
`, sessionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -274,11 +265,15 @@ func (s *Store) Undelivered(ctx context.Context, sessionID string) ([]Pending, e
|
||||
return pending, nil
|
||||
}
|
||||
|
||||
func (s *Store) MarkDelivered(ctx context.Context, responseIDs []string) error {
|
||||
func (s *Store) MarkDelivered(ctx context.Context, responseIDs []string, snapshotN int) error {
|
||||
return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
|
||||
at := now()
|
||||
var snap any
|
||||
if snapshotN > 0 {
|
||||
snap = snapshotN
|
||||
}
|
||||
for _, id := range responseIDs {
|
||||
_, err := tx.ExecContext(ctx, `UPDATE inbox_responses SET delivered_at = ? WHERE id = ?`, at, id)
|
||||
_, err := tx.ExecContext(ctx, `UPDATE inbox_responses SET delivered_at = ?, snapshot_n = ? WHERE id = ?`, at, snap, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -290,7 +285,7 @@ func (s *Store) MarkDelivered(ctx context.Context, responseIDs []string) error {
|
||||
func (s *Store) MarkUndelivered(ctx context.Context, responseIDs []string) error {
|
||||
return s.write(ctx, func(tx *sql.Tx, emit emitFunc) error {
|
||||
for _, id := range responseIDs {
|
||||
_, err := tx.ExecContext(ctx, `UPDATE inbox_responses SET delivered_at = NULL WHERE id = ?`, id)
|
||||
_, err := tx.ExecContext(ctx, `UPDATE inbox_responses SET delivered_at = NULL, snapshot_n = NULL WHERE id = ?`, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -306,7 +301,6 @@ type querier interface {
|
||||
|
||||
func getItem(ctx context.Context, q querier, id string) (api.InboxItem, error) {
|
||||
item := api.InboxItem{}
|
||||
kind := ""
|
||||
payload := ""
|
||||
state := ""
|
||||
createdAt := ""
|
||||
@@ -314,16 +308,15 @@ func getItem(ctx context.Context, q querier, id string) (api.InboxItem, error) {
|
||||
resolvedAt := sql.NullString{}
|
||||
|
||||
err := q.QueryRowContext(ctx, `
|
||||
SELECT id, project_id, task_id, agent_session_id, thread_id, kind, payload, state,
|
||||
SELECT id, project_id, task_id, agent_session_id, thread_id, payload, state,
|
||||
created_at, resolved_by, resolved_at
|
||||
FROM inbox_items WHERE id = ?
|
||||
`, id).Scan(&item.Id, &item.ProjectId, &item.TaskId, &item.AgentSessionId, &item.ThreadId, &kind,
|
||||
`, id).Scan(&item.Id, &item.ProjectId, &item.TaskId, &item.AgentSessionId, &item.ThreadId,
|
||||
&payload, &state, &createdAt, &resolvedBy, &resolvedAt)
|
||||
if err != nil {
|
||||
return item, err
|
||||
}
|
||||
|
||||
item.Kind = api.InboxItemKind(kind)
|
||||
item.State = api.InboxState(state)
|
||||
err = json.Unmarshal([]byte(payload), &item.Payload)
|
||||
if err != nil {
|
||||
@@ -347,7 +340,7 @@ func getItem(ctx context.Context, q querier, id string) (api.InboxItem, error) {
|
||||
|
||||
func getResponses(ctx context.Context, q querier, itemID string) ([]api.InboxResponse, error) {
|
||||
rows, err := q.QueryContext(ctx, `
|
||||
SELECT id, item_id, user_login, type, options, text, images, attachments, created_at, delivered_at
|
||||
SELECT id, item_id, user_login, type, options, text, images, attachments, created_at, delivered_at, snapshot_n
|
||||
FROM inbox_responses WHERE item_id = ? ORDER BY created_at
|
||||
`, itemID)
|
||||
if err != nil {
|
||||
@@ -365,8 +358,9 @@ func getResponses(ctx context.Context, q querier, itemID string) ([]api.InboxRes
|
||||
attachments := ""
|
||||
createdAt := ""
|
||||
delivered := sql.NullString{}
|
||||
snap := sql.NullInt64{}
|
||||
|
||||
err = rows.Scan(&r.Id, &r.ItemId, &r.User, &typ, &options, &text, &images, &attachments, &createdAt, &delivered)
|
||||
err = rows.Scan(&r.Id, &r.ItemId, &r.User, &typ, &options, &text, &images, &attachments, &createdAt, &delivered, &snap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -383,6 +377,10 @@ func getResponses(ctx context.Context, q querier, itemID string) ([]api.InboxRes
|
||||
if text.Valid {
|
||||
r.Text = &text.String
|
||||
}
|
||||
if snap.Valid {
|
||||
n := int(snap.Int64)
|
||||
r.SnapshotN = &n
|
||||
}
|
||||
err = json.Unmarshal([]byte(images), &r.Images)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -62,6 +62,14 @@ func (s *Store) LastSnapshot(ctx context.Context, taskID string) (api.Snapshot,
|
||||
return snap, err
|
||||
}
|
||||
|
||||
func (s *Store) LastSnapshotNot(ctx context.Context, taskID string, trigger api.SnapshotTrigger) (api.Snapshot, error) {
|
||||
snap, err := scanSnapshot(s.db.QueryRowContext(ctx, `SELECT `+snapshotColumns+` FROM snapshots WHERE task_id = ? AND trigger != ? ORDER BY n DESC LIMIT 1`, taskID, string(trigger)))
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return snap, ErrNotFound
|
||||
}
|
||||
return snap, err
|
||||
}
|
||||
|
||||
func (s *Store) LastTaskSeq(ctx context.Context, taskID string) (int64, error) {
|
||||
seq := int64(0)
|
||||
err := s.db.QueryRowContext(ctx, `SELECT COALESCE(MAX(seq), 0) FROM events WHERE task_id = ?`, taskID).Scan(&seq)
|
||||
|
||||
@@ -479,6 +479,23 @@ ALTER TABLE users ADD COLUMN default_model TEXT NOT NULL DEFAULT 'claude-opus-5-
|
||||
`}, {"add-team-members", `
|
||||
ALTER TABLE agent_sessions ADD COLUMN member TEXT NOT NULL DEFAULT '';
|
||||
ALTER TABLE task_inputs ADD COLUMN member TEXT NOT NULL DEFAULT '';
|
||||
`}, {"rename-inbox-tab", `
|
||||
UPDATE users SET focus = replace(focus, '"inbox"', '"questions"');
|
||||
`}, {"add-inbox-response-snapshots", `
|
||||
ALTER TABLE inbox_responses ADD COLUMN snapshot_n INTEGER;
|
||||
`}, {"errors-to-transcript", `
|
||||
UPDATE events SET kind = 'session.error', payload = json_object('error', json_extract(payload, '$.payload.error'))
|
||||
WHERE kind = 'inbox.created' AND json_extract(payload, '$.kind') = 'session_error';
|
||||
UPDATE events SET kind = 'session.rate_limited', payload = json_object(
|
||||
'vendor', json_extract(payload, '$.payload.vendor'),
|
||||
'rate_limit', json(json_extract(payload, '$.payload.rate_limit')),
|
||||
'error', json_extract(payload, '$.payload.error'))
|
||||
WHERE kind = 'inbox.created' AND json_extract(payload, '$.kind') = 'rate_limited';
|
||||
DELETE FROM events WHERE kind IN ('inbox.created', 'inbox.updated') AND json_extract(payload, '$.kind') != 'question';
|
||||
UPDATE events SET payload = json_remove(payload, '$.kind') WHERE kind IN ('inbox.created', 'inbox.updated');
|
||||
DELETE FROM inbox_responses WHERE item_id IN (SELECT id FROM inbox_items WHERE kind != 'question');
|
||||
DELETE FROM inbox_items WHERE kind != 'question';
|
||||
ALTER TABLE inbox_items DROP COLUMN kind;
|
||||
`}}
|
||||
|
||||
const (
|
||||
|
||||
Reference in New Issue
Block a user