acpmux: report when a person last prompted a chat, so a Cloud machine stays warm after a chat

Merged
TE
2d ago
+393-4

Summary

Leo asked to keep the user's machine warm for a while after a chat instead of pausing it at once. cmux-platform #798 (merged fe907c6b) keeps a NEXT Cloud machine running for CLOUD_POST_CHAT_WARM_SECONDS (600 s) after a person's chat turn ends, before the 120 s idle pause. It opens that window from a person's input in the guest's activity report: last_user_input_at (the terminal daemon: keys, mouse, paste) or activity.last_person_prompt_at (epoch ms, a person's prompt into a chat). No guest sent the second one, so a chat alone never opened the window: on prod the machine still paused 2 to 4 minutes after a chat, and the next message waited on a resume.

This sends it:

  • acpmux records when a person last sent a prompt into one of its chats (hub/person_prompt_at.rs). It counts at the session/prompt handler's existing person hook (server/agent_messages.rs person_prompt): a prompt with no agent's provenance (another agent's message, a tool's notice, a named sender), from a connection that is not a trigger (automation delivery) and carries no session caller token (a chat's own agent). What the daemon sends on its own (queued prompts, auto-resume, inbox digests) never goes through that path. A Cloud chat's prompt comes through a Web or peer connection, which never holds the person key, so this does not require the person-key proof that pair resumes need.
  • The Cloud activity line (daemon/cloud_activity.rs) carries it as last_person_prompt_at, and a new time goes at once instead of waiting for the 20 s renewal.
  • cmux-host keeps the newest time any acpmux daemon sent and puts it in cloud.vm.status.report's activity.last_person_prompt_at, the field and placement IdlePolicy.ts readPersonPromptAt and Vm.ts vmStatusReport read. A new prompt time is reported at once even while a turn runs, as terminal input is.

The time never moves backwards. Like the rest of the activity report (agent action times, counts) it lives in memory only, so a restarted daemon reports none until the next prompt.

No kill switch here: CLOUD_POST_CHAT_WARM_SECONDS=0 on the platform turns the warm window off, and the field is then ignored.

Prod needs a new VM image. The guest's acpmux and cmux-host come from the machine image, so nothing changes on Cloud until an image built from a feat-cmux-next commit with this change ships, and cmux-platform wrangler.jsonc pins it: CLOUD_VM_API_IMAGE / CLOUD_VM_API_IMAGE_REVISION for dev (top level, now cloud-native-f7b9c57), env.staging and env.production (now cloud-native-5e57723).

Testing

Ran on the fleet with cmux-ci test at this head:

  • cargo test -p acpmux --test person_prompt_activity: through real session/prompt requests on a hub, another agent's message (provenance) and a send from a session's own connection (caller token) leave last_person_prompt_at unset; the person's prompt sets it to about now; a later agent send leaves it there.
  • cargo test -p acpmux --lib -- cloud_activity person_prompt: the line carries the time, sends a new one at once, never moves it back, sends it again after an unsent line; an agent's action alone never sets it; the classification predicate; the hub time is monotonic.
  • cargo test -p cmux-host --lib cloud::: the report carries activity.last_person_prompt_at, a new one is reported while a turn runs, an older one or another daemon's line without it does not move it back, and the turn's end report still carries it.

Observed / Not run

Fleet run 41844408088 at 467182bfd93: cargo test -p cmux-host --lib cloud:: 143 passed, 0 failed (the new a_persons_prompt_time_reaches_the_report among them); cargo test -p acpmux --lib -- cloud_activity person_prompt 18 passed, 0 failed (a_persons_prompt_time_goes_at_once_and_never_moves_back, an_agents_action_is_no_persons_prompt, only_a_persons_prompt_counts, the_time_only_moves_forward listed ok); cargo test -p acpmux --test person_prompt_activity 1 passed. This is new behavior, so there is no red on the base to compare: the tests did not exist there.

Not run: a live Cloud machine (needs the image bump above), and the platform side end to end.

Changelog

Fixed: A Cloud machine stays running for a while after you chat with it, so your next message does not wait for it to resume (once the new machine image ships).

Agent session: agent session

šŸ¤– Generated with Claude Code