fix(inbox): keep an agent's notice in Needs you until acknowledged
Merged
DA
5d ago+590+590+012345678901234567890123456789-68-68-01234567890123456789
What was asked
The developer: "I think my agents are sending me things in my inbox but I'm not seeing them in Needs you because they don't require an answer - let's fix that and still show them in needs you until acknowledged even if we aren't sending anything back to the agent if the user has nothing to say."
Before this change, a post_to_inbox with no ask wrote its item as already answered, so it never showed in Needs you, the sidebar count, or Home.
What changed
Store (packages/service/src/inbox/inbox-store.ts)
- A post that asks nothing now opens its item as a notice: status
open, responsenone,needsReply: false, no blocks. This applies to a new thread, and to a follow-up with no ask on a thread that holds no open ask, such as one already answered or closed. That follow-up rewrites the item as a notice, moves its revision on, and puts it back in Needs you. A follow-up on a thread whose ask is still open stays a plain message, as before. - A notice does not count toward the agent's 20-open-ask limit (
countOpenBesides). The agent'swithdraw_ask(closeItem) does not find it, because it holds no ask. - A member's message on an open notice settles it as their nod (
answered,{ reply: acknowledged }, under the message's key). If handing the message to the agent fails,withdrawInboxMessagedeletes the message and reopens the notice, so the thread never shows a message the agent wasn't told.
Got it
- This reuses the existing answer-by-revision path with
INBOX_REPLY.ACKNOWLEDGED. Because a notice hasneedsReply: false, a bare Got it reaches nobody: no message, no turn. A Got it with a typed note still reaches the agent, as an answer does today. - Older desktops (before v5) already draw an open item with response
noneas a note with a Got it press, and that press goes through this same path. - The panel (
inbox-answer-box.tsx,inbox-model.ts's newawaitsNod) shows Got it on an open notice thread while the box is empty, and Reply once it holds words or files. The quiet line says whether the agent will be messaged. - Closing a notice without acknowledging works as before, and tells the agent nothing.
What the agent reads (coder-host/inbox.ts)
- In
read_inbox, an open notice showsstatus: open, with nowaitsand none of the empty legacyblocks/response, so it doesn't look like an open ask. Once acknowledged it reads as answered withanswer: { reply: acknowledged }. - The
post_to_inboxtool description is unchanged. Its line that a post without an ask "asks nothing" is still true from the agent's side.
Notes
- No migration, no wire version bump, no schema change.
- Existing notices are not backfilled: ones already settled stay settled. Only new posts open as notices.
Decisions after review (approved by the orchestrator)
- Open notices are capped. An agent may hold at most
MAX_OPEN_PER_AGENT(20) open notices, counted apart from its open asks. A post past the cap is refused with "Not posted: the developer has 20 notices of yours to acknowledge. Follow up on one under its key, or wait until they do." A follow-up under a key whose notice is already open is not refused. No notice is ever settled without the developer's nod. Thepost_to_inboxdescription now says a post without an ask waits until it is acknowledged, and counts toward that cap. - A reply settles only the notice the member saw. The message request (
inboxMessageRequestSchema, hostedinbox.message) gains an optionalrevision, an additive field with no wire version bump. When the panel replies on a notice it sendsitem.revision. The store settles the notice only where it still stands at that revision, so a reply to an earlier thread never settles a notice posted since. A client that sends no revision settles nothing by message. The JSON Schema goldens for the message request and params were regenerated withLUKE_UPDATE_FIXTURES=1; the only change is the new optionalrevision. - New tests: the notice cap at the store and through the tool's refusal, a stale or missing revision settling nothing, and in the panel, Got it answering at the notice's revision and Reply sending it.
Tests
inbox-threads.test.ts(store, PGlite):- notices stay open and count in the account's waiting read
- a follow-up on an answered thread brings it back
- Got it settles a notice without writing a message
- a member's close settles a notice
- a member's words settle a notice, and taking them back reopens it
- the agent's withdrawal finds no ask on a notice
- 20 open notices don't block an ask
coder-inbox.test.ts: the agent's read of a notice has no ask fields, andwithdraw_askrefuses it.coding-agents-app.test.ts: through the routes, Got it messages nobody, a reply with words reaches the agent, and both settle the item.inbox-model.test.ts:awaitsNod, and the Got it reply it sends.pnpm check:affected: every task passed, but in this 8 GB sandbox some typechecks were killed for running out of memory (exit 137) when run in parallel. Each of those passed when run alone.test:storeran on PGlite here; CI's Postgres job runs it on Postgres.
Made with Luke