mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-02 14:28:59 +02:00
[eric] canvas: stopping a workflow run keeps its card, because you stopped it to read it (ENG-420)
This commit is contained in:
@@ -42,3 +42,41 @@ test('notifications are still a separate question from cards', () => {
|
||||
assert.equal(deservesCanvasCard(run('running')), true);
|
||||
assert.equal(isUserLaunchedSession(run('running')), false);
|
||||
});
|
||||
|
||||
// ENG-420: stopping a workflow-backed agent closed its whole card. Haik, production 1.7.9:
|
||||
// "Stop should mean stop, not close" -- you lose the transcript the moment you stop the run, which
|
||||
// is the thing you stopped it to read. The despawn rule could not tell "the nightly run finished"
|
||||
// from "a person pressed Stop", and it was written for the first one.
|
||||
test('a run a HUMAN stopped keeps its card', () => {
|
||||
assert.equal(deservesCanvasCard({
|
||||
mode: 'agent', workflow_run_id: 'r1', status: 'stopped', ended_by_user: true,
|
||||
}), true);
|
||||
});
|
||||
|
||||
test('a run that ended on its own still despawns', () => {
|
||||
// The litter case the rule exists for: a nightly workflow must not leave a card behind every night.
|
||||
for (const status of ['completed', 'stopped', 'error']) {
|
||||
assert.equal(deservesCanvasCard({ mode: 'agent', workflow_run_id: 'r1', status }), false, status);
|
||||
}
|
||||
});
|
||||
|
||||
test('Close still dismisses it, even though Close also sets ended_by_user', () => {
|
||||
// Both routes stamp ended_by_user; only Close stamps closed_at, which is what separates them.
|
||||
assert.equal(deservesCanvasCard({
|
||||
mode: 'agent', workflow_run_id: 'r1', status: 'stopped',
|
||||
ended_by_user: true, closed_at: '2026-08-28T00:00:00Z',
|
||||
}), false);
|
||||
});
|
||||
|
||||
test('a live run is unaffected either way', () => {
|
||||
for (const status of ['running', 'waiting_approval']) {
|
||||
assert.equal(deservesCanvasCard({ mode: 'agent', workflow_run_id: 'r1', status }), true, status);
|
||||
assert.equal(deservesCanvasCard({
|
||||
mode: 'agent', workflow_run_id: 'r1', status, ended_by_user: true,
|
||||
}), true, `${status} + stopped flag`);
|
||||
}
|
||||
});
|
||||
|
||||
test('a user-launched chat never depends on any of this', () => {
|
||||
assert.equal(deservesCanvasCard({ mode: 'agent', status: 'stopped' }), true);
|
||||
});
|
||||
|
||||
@@ -6,6 +6,10 @@ export interface SessionOrigin {
|
||||
mode: string;
|
||||
workflow_run_id?: string | null;
|
||||
workflow_edit_id?: string | null;
|
||||
// A human pressed Stop or Close. Set by those two routes only; a watchdog's stop never sets it.
|
||||
ended_by_user?: boolean;
|
||||
// Set by Close, never by Stop. It is what tells the two apart here.
|
||||
closed_at?: string | null;
|
||||
}
|
||||
|
||||
/** A run that is still working, so its card is worth having on screen. */
|
||||
@@ -29,8 +33,18 @@ export function isUserLaunchedSession(session: SessionOrigin): boolean {
|
||||
* the dock path is gated on the parent card existing, so no card meant no owner. Give the run a card
|
||||
* and the existing inline-dock plus despawn logic applies to it unchanged. The card goes when the run
|
||||
* stops, or a nightly workflow would leave one behind every single night.
|
||||
*
|
||||
* EXCEPT when a human stopped it. "Ends on its own" and "a person hit Stop" are different events and
|
||||
* this could not tell them apart, so pressing Stop on a workflow-backed agent made its card vanish
|
||||
* along with the transcript the user stopped it to read (ENG-420). Someone stops a run to LOOK at
|
||||
* it; the nightly-litter case it was written for is the one that ends by itself, which still
|
||||
* despawns. Close is what dismisses a card, and Close is the only route that stamps `closed_at`.
|
||||
*/
|
||||
export function deservesCanvasCard(session: SessionOrigin & { status?: string }): boolean {
|
||||
export function deservesCanvasCard(
|
||||
session: SessionOrigin & { status?: string },
|
||||
): boolean {
|
||||
if (isUserLaunchedSession(session)) return true;
|
||||
return !!session.workflow_run_id && LIVE_STATUSES.has(session.status ?? '');
|
||||
if (!session.workflow_run_id) return false;
|
||||
if (LIVE_STATUSES.has(session.status ?? '')) return true;
|
||||
return !!session.ended_by_user && !session.closed_at;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user