From 04e36851b7f8554562bea071310ec675c5da571c Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Thu, 16 Apr 2026 15:41:44 -0500 Subject: [PATCH] =?UTF-8?q?feat(tui):=20honest=20status=20'starting=20agen?= =?UTF-8?q?t=E2=80=A6'=20until=20session.info=20arrives?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Post-async-session.create, `session.create` returns in ~1ms with partial info and the real agent fires `session.info` ~1s later. Previously the status bar went straight to 'ready' right after the instant RPC return, which was misleading — `prompt.submit` would block server-side waiting for the agent to finish building. Now: - `newSession`: status = 'starting agent…' when info has no `version`, else 'ready' (covers the fast resume path too) - `session.info` event: flips status to 'ready' only if it was 'starting agent…', preserving running/interrupted/error states --- ui-tui/src/app/createGatewayEventHandler.ts | 3 +++ ui-tui/src/app/useSessionLifecycle.ts | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ui-tui/src/app/createGatewayEventHandler.ts b/ui-tui/src/app/createGatewayEventHandler.ts index 63a306b04..adb6d4f55 100644 --- a/ui-tui/src/app/createGatewayEventHandler.ts +++ b/ui-tui/src/app/createGatewayEventHandler.ts @@ -165,6 +165,9 @@ export function createGatewayEventHandler(ctx: GatewayEventHandlerContext): (ev: patchUiState(state => ({ ...state, info: ev.payload, + // Flip from 'starting agent…' → 'ready' when the agent is live. + // Leave running/interrupted/error statuses alone. + status: state.status === 'starting agent…' ? 'ready' : state.status, usage: ev.payload.usage ? { ...state.usage, ...ev.payload.usage } : state.usage })) // Agent init is async in session.create, so the intro message may diff --git a/ui-tui/src/app/useSessionLifecycle.ts b/ui-tui/src/app/useSessionLifecycle.ts index bbde757cf..9fed9fe98 100644 --- a/ui-tui/src/app/useSessionLifecycle.ts +++ b/ui-tui/src/app/useSessionLifecycle.ts @@ -104,7 +104,16 @@ export function useSessionLifecycle(opts: UseSessionLifecycleOptions) { resetSession() setSessionStartedAt(Date.now()) - patchUiState({ info: r.info ?? null, sid: r.session_id, status: 'ready', usage: usageFrom(r.info ?? null) }) + // Python's `session.create` returns instantly with partial info (no `version` + // field); the `session.info` event will flip status to 'ready' once the + // agent is fully built (~1s later). Until then prompt.submit will block + // server-side on `_wait_agent`. + patchUiState({ + info: r.info ?? null, + sid: r.session_id, + status: r.info?.version ? 'ready' : 'starting agent…', + usage: usageFrom(r.info ?? null) + }) if (r.info) { setHistoryItems([introMsg(r.info)])