Skip to content

Forget what a Bot did on the computer that was just reset - #367

Open
zopeVaibhav wants to merge 1 commit into
CopilotKit:mainfrom
zopeVaibhav:fix/clear-activity-on-computer-reset
Open

Forget what a Bot did on the computer that was just reset#367
zopeVaibhav wants to merge 1 commit into
CopilotKit:mainfrom
zopeVaibhav:fix/clear-activity-on-computer-reset

Conversation

@zopeVaibhav

Copy link
Copy Markdown
Contributor

Closes #366

What this changes

Resetting a Bot's computer deletes the browser profile it worked on. The activity pane beside the
chat did not hear about it, so the commands and file operations from the wiped profile stayed on
screen, sitting alongside anything the Bot did afterwards with nothing to tell the two apart. Only a
full page reload cleared them, which is likely why it went unnoticed: reaching Admin by typing the
URL reloads the app and empties the store, and the bug only shows when somebody navigates there and
back through the sidebar.

The pane is a module-level store in the browser keyed by Bot id (byComputer in
app/src/lib/computers/activity.ts), and a reset does not change that id, so the entry survives it.
Invalidating computerKeys.all does not reach the store, because the pane is browser-session state
rather than a query.

clearActivity already exists and already carries this exact reasoning in its own comment —
"Wiping a computer deletes the machine those commands ran on, so leaving them on screen would
describe something that no longer exists." Nothing in the tree called it. This adds the one call site
it was written for, in the onSuccess of setComputerStateMutationOptions.

Guarded on action === "reset". Stopping a browser keeps the profile and is meant to resume where it
left off, so its history is still true of the machine the Bot gets handed back, and clearing it there
would be the same kind of lie in the other direction.

Nothing else changes. The audit trail, which is the record, was correct throughout and is untouched.
The server, the gateway and the computer routes are not modified.

Where it runs

  • New state that outlives a request? None. This removes entries from a store that already
    existed rather than adding one. The store is byComputer and browsed in
    app/src/lib/computers/activity.ts, module-level in the browser tab and deliberately so: it is
    a live view of what this session watched happen, not a record. The record is the audit trail,
    which is in Postgres and which this does not touch.
  • What happens on the second replica? Nothing changes. No server process is involved. The
    reset request already goes to whichever process the load balancer picks and is already
    answered the same way by any of them; this only decides what the browser that sent it does
    with its own pane afterwards.
  • Anything serialised? No. There is one writer — the tab that ran the mutation — and it acts
    on its own memory after its own request succeeded.
  • Anything fanned out to a browser? No, and this is the honest limit of the change. A reset
    performed in one tab does not clear the pane in another tab, or on another person's screen
    watching the same Bot. That is unchanged behaviour: the pane never crossed tabs, because it is
    fed by the component that watched the run rather than by a socket. Making the reset itself
    travel would mean carrying it on the channel events socket and giving the pane a subscription,
    which is a real feature rather than a wiring gap, and is worth deciding separately. The failure
    this leaves is strictly smaller than the one it removes: the tab that pressed Reset is the one
    whose screen was lying to the person who pressed it.
  • New listener, port, or schedule? None.

Boundary and audit

  • Every acting call still goes through the gateway: resolve, decide, audit, then act. The reset
    call itself is untouched — it is still the same POST through client, and the
    computer.reset row still lands. This runs after that call has already succeeded.
  • New refusals and new failures each write a row. No new refusal or failure path is introduced.
    A failed reset does not reach onSuccess, so a reset that was refused leaves the pane exactly
    as it was, which is correct: nothing was wiped.
  • Nothing new is trusted from the client that the server can resolve itself. Nothing new is sent
    to or read from the server. The botId used is the one the browser just sent in its own
    request URL.

Changelog

  • A line in CHANGELOG.md under Unreleased.

Proof

Reproduced first, on fb999b1, before touching anything.

  1. bun run dev against a deployment with a Bot that has a computer.
  2. Ask it in a channel to run echo repro-marker-bravo.
  3. The pane beside the chat lists the command and its output under Activity.
  4. Without reloading, reach Admin → Computers through the sidebar, press Reset, confirm.
    POST /api/computers/general-assistant/computers/reset returns 200 and a computer.reset row
    lands in the audit trail.
  5. Return to the channel through the sidebar, not the address bar.
  6. The pane still lists the command from step 2, describing a profile that no longer exists.

After the change, step 6 shows an empty pane.

Regression test. app/tests/computer-reset-clears-activity.test.ts, three cases: a reset forgets
that Bot's history, a stop keeps it, and one Bot's reset leaves another Bot's history alone.

Control run. With the onSuccess restored to () => invalidateComputers(queryClient) and the
test file unchanged, 2 of the 3 fail:

error: expect(received).toEqual(expected)

- []
+ [
+   {
+     "kind": "command",
+     "subject": "echo repro-marker-bravo",
+     "output": "repro-marker-bravo\n",
+     "exitCode": 0,
+   },
+ ]

 1 pass
 2 fail

The one that still passes is the stop case, which asserts the history survives — it should pass
either way, and a version of this test where it did not would be testing the wrong thing.

Checks, on this branch.

bun test app/tests   213 pass, 0 fail, 35 files
bun run typecheck    app, server, worker — all exit 0
bun run lint         522 files, no findings
bunx biome format .  519 files, no fixes applied
bun run build        exit 0

The server/tests routine-queue and agent-handoff integration suites are flaky on a clean checkout
of main here and were not used as a signal; this branch changes no server file.

@zopeVaibhav
zopeVaibhav force-pushed the fix/clear-activity-on-computer-reset branch from 026527c to 390cb4b Compare September 4, 2026 18:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Resetting a Bot's computer leaves the commands it ran on screen, describing a machine that no longer exists

1 participant