Mark the lead's messages and answers as the lead's, not the human's

This commit is contained in:
Ian Gulliver
2026-10-20 12:20:51 -07:00
parent 181482e5d0
commit 0f33ad4524
14 changed files with 93 additions and 23 deletions
+6 -5
View File
@@ -531,6 +531,7 @@ func deliveryMessage(pending []store.Pending) string {
b := &strings.Builder{}
for i, p := range pending {
r := p.Response
who := actorName(r.User)
if i > 0 {
b.WriteString("\n")
}
@@ -540,27 +541,27 @@ func deliveryMessage(pending []store.Pending) string {
switch r.Type {
case api.Option:
if p.Item.Payload["multiple"] == true {
fmt.Fprintf(b, "%s checked:\n", r.User)
fmt.Fprintf(b, "%s checked:\n", who)
for _, o := range *r.Options {
fmt.Fprintf(b, "- %s\n", o)
}
} else {
fmt.Fprintf(b, "%s chose: %s\n", r.User, (*r.Options)[0])
fmt.Fprintf(b, "%s chose: %s\n", who, (*r.Options)[0])
}
if r.Text != nil && strings.TrimSpace(*r.Text) != "" {
fmt.Fprintf(b, "%s added: %s\n", r.User, *r.Text)
fmt.Fprintf(b, "%s added: %s\n", who, *r.Text)
}
case api.Other:
text := ""
if r.Text != nil {
text = *r.Text
}
fmt.Fprintf(b, "%s answered (none of your options): %s\n", r.User, text)
fmt.Fprintf(b, "%s answered (none of your options): %s\n", who, 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 {
fmt.Fprintf(b, "%s attached %d image(s) to this response; they come with this message.\n", r.User, len(r.Images))
fmt.Fprintf(b, "%s attached %d image(s) to this response; they come with this message.\n", who, len(r.Images))
}
for _, a := range r.Attachments {
+19 -1
View File
@@ -49,6 +49,24 @@ func isLeadActor(actor string) bool {
return strings.HasSuffix(actor, " (lead)")
}
func leadOwner(actor string) string {
return strings.TrimSuffix(actor, " (lead)")
}
func actorName(actor string) string {
if !isLeadActor(actor) {
return actor
}
return leadOwner(actor) + "'s lead agent"
}
func agentText(actor, text string) string {
if !isLeadActor(actor) {
return text
}
return fmt.Sprintf("This message is from %s, not from %s:\n\n%s", actorName(actor), leadOwner(actor), text)
}
func humanActor(actor string) bool {
return actor != "byre" && actor != agentActor && actor != boardActor && !strings.HasSuffix(actor, leadActor(""))
}
@@ -645,7 +663,7 @@ func (m *Manager) answeredText(ctx context.Context, item api.InboxItem) string {
answer = strings.TrimSpace(answer + " " + *r.Text)
}
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))
return fmt.Sprintf("%s: %s answered question %s %q: %s\nThe agent recommended: %s", m.taskLabel(ctx, item.TaskId), actorName(r.User), item.Id, clip(fmt.Sprint(item.Payload["question"]), 300), clip(answer, 600), clip(recommended, 600))
}
func remarshal(from any, to any) error {
+2 -2
View File
@@ -139,7 +139,7 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
m.mu.Lock()
m.leadAnswered[c.ItemId] = true
m.mu.Unlock()
_, err = m.Respond(ctx, user.Login, []api.InboxResponseCreate{c})
_, err = m.Respond(ctx, leadActor(user.Login), []api.InboxResponseCreate{c})
if err != nil {
m.mu.Lock()
delete(m.leadAnswered, c.ItemId)
@@ -1056,7 +1056,7 @@ func transcriptLine(ev api.Event, root string) string {
case boardActor:
return ""
}
return ev.Actor + ": " + text("text")
return actorName(ev.Actor) + ": " + text("text")
case "board.posted":
return fmt.Sprintf("board post by %s: %s", postAuthor(ev), text("text"))
case "agent.message":
+2 -2
View File
@@ -603,7 +603,7 @@ func (m *Manager) deliver(ctx context.Context, sess api.AgentSession, task api.T
}
m.beginTurn(l, compacting)
err = m.send(ctx, l, text, imgs)
err = m.send(ctx, l, agentText(actor, text), imgs)
if err != nil {
m.endMergeTurn(sess.Id, false)
return err
@@ -684,7 +684,7 @@ func (m *Manager) message(ctx context.Context, sess api.AgentSession, task api.T
return err
}
m.beginTurn(l, compacting)
return m.send(ctx, l, text, imgs)
return m.send(ctx, l, agentText(actor, text), imgs)
}
func (m *Manager) send(ctx context.Context, l *live, text string, imgs []image) error {
+5 -4
View File
@@ -92,18 +92,19 @@ func decisionLine(item api.InboxItem, r api.InboxResponse) string {
if r.Text != nil {
text = strings.TrimSpace(*r.Text)
}
who := actorName(r.User)
switch r.Type {
case api.Option:
line := fmt.Sprintf("%s chose: %s\n", r.User, strings.Join(*r.Options, "; "))
line := fmt.Sprintf("%s chose: %s\n", who, strings.Join(*r.Options, "; "))
if item.Payload["multiple"] == true {
line = fmt.Sprintf("%s checked: %s\n", r.User, strings.Join(*r.Options, "; "))
line = fmt.Sprintf("%s checked: %s\n", who, strings.Join(*r.Options, "; "))
}
if text != "" {
line += fmt.Sprintf("%s added: %s\n", r.User, text)
line += fmt.Sprintf("%s added: %s\n", who, text)
}
return line
case api.Other:
return fmt.Sprintf("%s answered: %s\n", r.User, text)
return fmt.Sprintf("%s answered: %s\n", who, text)
}
return ""
}
+4
View File
@@ -267,6 +267,10 @@ func (m *Manager) recordQueued(ctx context.Context, l *live, msgs []queued) stri
fmt.Fprintf(b, "While you were working, %s\n\nTake it into account now.", q.text)
continue
}
if isLeadActor(q.actor) {
fmt.Fprintf(b, "%s (not %s) sent you this message while you were working; take it into account now:\n\n%s", actorName(q.actor), leadOwner(q.actor), q.text)
continue
}
fmt.Fprintf(b, "%s sent you this message while you were working; take it into account now:\n\n%s", q.actor, q.text)
}
slog.Info("queued messages sent mid-turn", "session", l.id, "count", len(msgs))
+1 -1
View File
@@ -172,7 +172,7 @@ func (m *Manager) post(ctx context.Context, task api.Task, from poster, text str
return err
}
who := from.actor
who := actorName(from.actor)
if from.member != "" {
who = fmt.Sprintf("%q", from.member)
}