From d0c596dcaa2506e8c6920be053ebf9b70805ded3 Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Thu, 5 Mar 2026 17:08:55 +0100 Subject: [PATCH] Add mail_history.sh script for parsing agent message history --- cmd/Assist/main.go | 36 ++++++++++++++++++++++++++++++- cmd/anvillm/main.go | 2 +- internal/supervisor/supervisor.go | 3 ++- scripts/mail_history.sh | 35 ++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 3 deletions(-) create mode 100755 scripts/mail_history.sh diff --git a/cmd/Assist/main.go b/cmd/Assist/main.go index 414b328..2f6ca62 100644 --- a/cmd/Assist/main.go +++ b/cmd/Assist/main.go @@ -422,7 +422,37 @@ func isBeadID(text string) bool { return matched } +func getMountForSession(sessionID string) string { + sess, err := getSession(sessionID) + if err != nil || sess.Cwd == "" { + return "" + } + data, err := readFile("beads/mtab") + if err != nil { + return "" + } + for _, line := range strings.Split(string(data), "\n") { + parts := strings.Split(line, "\t") + if len(parts) == 2 { + mountName, mountCwd := parts[0], parts[1] + if sess.Cwd == mountCwd || strings.HasPrefix(sess.Cwd, mountCwd+"/") { + return mountName + } + } + } + return "" +} + func sendPrompt(id, prompt string) error { + mount := "" + trimmedPrompt := strings.TrimSpace(prompt) + if isBeadID(trimmedPrompt) { + mount = getMountForSession(id) + } + return sendPromptWithMount(id, prompt, mount) +} + +func sendPromptWithMount(id, prompt, mount string) error { if !isConnected() { return fmt.Errorf("not connected to anvilsrv") } @@ -430,7 +460,11 @@ func sendPrompt(id, prompt string) error { // Check if prompt is a bead ID and construct execution prompt trimmedPrompt := strings.TrimSpace(prompt) if isBeadID(trimmedPrompt) { - prompt = fmt.Sprintf("Load the beads skill, and work on bead %s.", trimmedPrompt) + if mount != "" { + prompt = fmt.Sprintf("Load the beads skill, and work on bead %s, mount=%s.", trimmedPrompt, mount) + } else { + prompt = fmt.Sprintf("Load the beads skill, and work on bead %s.", trimmedPrompt) + } } // Create message JSON diff --git a/cmd/anvillm/main.go b/cmd/anvillm/main.go index fb467a9..141ff98 100644 --- a/cmd/anvillm/main.go +++ b/cmd/anvillm/main.go @@ -1749,7 +1749,7 @@ func showAssignBeadConfirm(bead map[string]interface{}) { form.SetButtonTextColor(tcell.ColorBlack) form.AddButton("Yes", func() { // Send prompt to work on the bead - prompt := fmt.Sprintf("Work on bead %s", beadID) + prompt := fmt.Sprintf("Work on bead %s, mount=%s", beadID, currentMount) if err := sendPrompt(sess.ID, prompt); err != nil { updateStatus(fmt.Sprintf("[red]Error sending prompt: %v", err)) } else { diff --git a/internal/supervisor/supervisor.go b/internal/supervisor/supervisor.go index 822c45f..8692e1a 100644 --- a/internal/supervisor/supervisor.go +++ b/internal/supervisor/supervisor.go @@ -89,13 +89,14 @@ func (s *Supervisor) assignWork() { } beadID := bead["id"].(string) + mountName := filepath.Base(taskCwd) // Skip if already assigned if _, assigned := s.assigned[beadID]; assigned { continue } - msg := mailbox.NewMessage("supervisor", botID, mailbox.MessageTypePromptRequest, "work", "Work on bead "+beadID+".") + msg := mailbox.NewMessage("supervisor", botID, mailbox.MessageTypePromptRequest, "work", "Work on bead "+beadID+", mount="+mountName+".") s.mailbox.DeliverToInbox(botID, msg) s.lastAssigned[botID] = time.Now().Unix() s.assigned[beadID] = botID diff --git a/scripts/mail_history.sh b/scripts/mail_history.sh new file mode 100755 index 0000000..cd0a935 --- /dev/null +++ b/scripts/mail_history.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Parse and display message history for an agent or user +set -euo pipefail + +AGENT_ID="${1:-}" +DATE_FILTER="${2:-}" +if [[ -z "$AGENT_ID" ]]; then + echo "Usage: $0 [YYYYMMdd]" >&2 + exit 1 +fi + +MAIL_DIR="$HOME/.local/share/anvillm/mail/$AGENT_ID" + +shopt -s nullglob +if [[ -n "$DATE_FILTER" ]]; then + SENT="$MAIL_DIR/${DATE_FILTER}-sent.jsonl" + RECV="$MAIL_DIR/${DATE_FILTER}-recv.jsonl" + FILES=() + [[ -f "$SENT" ]] && FILES+=("$SENT") || echo "Could not get sent messages for $DATE_FILTER" >&2 + [[ -f "$RECV" ]] && FILES+=("$RECV") || echo "Could not get received messages for $DATE_FILTER" >&2 +else + FILES=("$MAIL_DIR"/*-sent.jsonl "$MAIL_DIR"/*-recv.jsonl) +fi +shopt -u nullglob + +if [[ ${#FILES[@]} -eq 0 ]]; then + echo "No messages for $AGENT_ID" + exit 0 +fi + +cat "${FILES[@]}" | jq -rs 'sort_by(.ts) | .[] | +"\(.ts | strftime("%Y-%m-%d %H:%M:%S")) [\(.data.type)] \(.data.from) → \(.data.to) + Subject: \(.data.subject) + \(.data.body | split("\n") | join("\n ")) +"'