You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Agent conversations: build the sender's side from delivered messages so both threads always match #4788
PR #4772 shows agent-to-agent conversations on both threads. The receiving thread renders each delivered message as "Message from " with its answer as "Reply to ". The sending thread renders "Message to " / "Reply from ", but it builds those chips by parsing bb thread tell commands in its own timeline. Any message delivered with that thread as sender that its agent did not send with a bb thread tell shell command appears on the receiver's side only, so the two timelines can disagree.
Proposal: build the sender's view from the receiver's records (every delivered message whose senderThreadId is this thread) instead of from command text. The two sides then match by construction.
macOS (Darwin 25.5), Node 22.23.1, pnpm dev branch web app.
Provider: Claude Code, claude-haiku-4-5-20251001.
Steps to reproduce
With PR #4772 checked out and pnpm dev running, in a shell with the dev CLI (pnpm bb:dev):
Create two threads, A ("Release manager") and B ("Calendar worker"), in the same project.
Send B a message attributed to A without A's agent running a command:
BB_THREAD_ID=<A> pnpm -s bb:dev thread tell <B>"Is the cache TTL the cause? One short sentence."
Wait for B to answer, then open both threads in the app.
Also reproduces when A's agent sends with a form the parser doesn't recognize. Examples: an unusual shell wrapper, --message-file pointing at a file (the chip renders without text), or any SDK/API send that sets senderThreadId.
Expected vs actual
Expected: B shows "Message from A" + "Reply to A", and A shows the matching "Message to B" + "Reply from B".
Actual: B shows "Message from A" + "Reply to A". A shows nothing for that exchange. During QA for Tell agents to answer other agents with bb thread tell #4772, B showed 5 messages from A while A's timeline showed 1, the only one its agent had sent itself.
When A's agent does send with bb thread tell, both sides match. Verified with four agent-driven rounds: 4 sent, 4 received.
queued_thread_messages.sender_thread_id while queued (schema.ts).
There is no query or route that lists messages by sender thread.
Proposed approach
Server: add a read route, with SDK and CLI parity per AGENTS.md, that returns messages delivered with senderThreadId = <thread>. Each entry carries the recipient thread, message text, request status, delivered-at time, the recipient turn id, and that turn's final assistant text once the turn settles. This likely needs an indexed sender column, or a small table written at send time, rather than JSON scans over thread_events.
App: render the sender's "Message to" / "Reply from" chips from that route, placed in the sender's timeline by delivery time. Drop the command parsing and the text/time reply heuristic. The receiver side stays as in Tell agents to answer other agents with bb thread tell #4772.
Decide: whether bb thread tell command rows stay visible in the sender's work summary once the chips no longer depend on them.
Not fixable in the client alone. The sender's timeline has no record of a send that did not happen through its own shell, and scanning every other thread's timeline client-side doesn't scale.
Suggested priority and effort
Medium priority, medium effort. Agent-driven sends, the common case, already match after #4772. The mismatch hits manual or SDK sends and unusual command forms, and nothing is lost: the receiver still has the full record.
Summary
PR #4772 shows agent-to-agent conversations on both threads. The receiving thread renders each delivered message as "Message from " with its answer as "Reply to ". The sending thread renders "Message to " / "Reply from ", but it builds those chips by parsing
bb thread tellcommands in its own timeline. Any message delivered with that thread as sender that its agent did not send with abb thread tellshell command appears on the receiver's side only, so the two timelines can disagree.Proposal: build the sender's view from the receiver's records (every delivered message whose
senderThreadIdis this thread) instead of from command text. The two sides then match by construction.Versions and environment
64469e0942(PR Tell agents to answer other agents with bb thread tell #4772 head), basemainat4ee89642c8.pnpm devbranch web app.claude-haiku-4-5-20251001.Steps to reproduce
With PR #4772 checked out and
pnpm devrunning, in a shell with the dev CLI (pnpm bb:dev):Also reproduces when A's agent sends with a form the parser doesn't recognize. Examples: an unusual shell wrapper,
--message-filepointing at a file (the chip renders without text), or any SDK/API send that setssenderThreadId.Expected vs actual
When A's agent does send with
bb thread tell, both sides match. Verified with four agent-driven rounds: 4 sent, 4 received.Evidence
agent-thread-tell-command.tsAgentSentMessageRow.tsxagent-sent-message-reply.ts.senderThreadId(stored-thread-event.ts);queued_thread_messages.sender_thread_idwhile queued (schema.ts).Proposed approach
senderThreadId = <thread>. Each entry carries the recipient thread, message text, request status, delivered-at time, the recipient turn id, and that turn's final assistant text once the turn settles. This likely needs an indexed sender column, or a small table written at send time, rather than JSON scans overthread_events.bb thread tellcommand rows stay visible in the sender's work summary once the chips no longer depend on them.What I ruled out
Suggested priority and effort
Medium priority, medium effort. Agent-driven sends, the common case, already match after #4772. The mismatch hits manual or SDK sends and unusual command forms, and nothing is lost: the receiver still has the full record.
Related: #4772
BB-Thread-ID: thr_4u5mgu9qe7