mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-08 02:37:45 +02:00
[eric] agents: mid-turn provider backoff shows a muted retrying pill instead of a dead card, and transient pills survive session status frames
This commit is contained in:
@@ -118,6 +118,7 @@ export interface AgentSession {
|
||||
framework_overhead_tokens?: number;
|
||||
context_overflow?: { reason: string; message: string; at: string } | null;
|
||||
rate_limited?: { retry_after_s: number | null; at: string } | null;
|
||||
provider_retrying?: { attempt: number | null; delay_ms: number | null; at: string } | null;
|
||||
context_recovered?: { at: string } | null;
|
||||
// Set when a view-builder turn installed/changed deps, so the app card does a HARD reload (Vite restart) at turn-finish instead of the soft one. Reset when the next turn starts.
|
||||
app_deps_changed?: boolean;
|
||||
@@ -741,6 +742,9 @@ const agentsSlice = createSlice({
|
||||
branches: { ...existing?.branches, ...action.payload.branches },
|
||||
pending_approvals: mergedApprovals,
|
||||
tool_group_meta: { ...existing?.tool_group_meta, ...action.payload.tool_group_meta },
|
||||
// Renderer-local transient pills; the wire payload never carries them, so a status frame mid-backoff would wipe the "provider busy" pill it exists to explain.
|
||||
provider_retrying: existing?.provider_retrying ?? null,
|
||||
rate_limited: existing?.rate_limited ?? null,
|
||||
};
|
||||
if (action.payload.status === 'running' && !state.trackedNotificationIds.includes(action.payload.id)) {
|
||||
state.trackedNotificationIds.push(action.payload.id);
|
||||
@@ -1003,6 +1007,23 @@ const agentsSlice = createSlice({
|
||||
}
|
||||
},
|
||||
|
||||
setProviderRetrying(
|
||||
state,
|
||||
action: PayloadAction<{ sessionId: string; attempt: number | null; delayMs: number | null }>
|
||||
) {
|
||||
const session = state.sessions[action.payload.sessionId];
|
||||
if (session) {
|
||||
session.provider_retrying = {
|
||||
attempt: action.payload.attempt,
|
||||
delay_ms: action.payload.delayMs,
|
||||
at: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
},
|
||||
clearProviderRetrying(state, action: PayloadAction<{ sessionId: string }>) {
|
||||
const session = state.sessions[action.payload.sessionId];
|
||||
if (session) session.provider_retrying = null;
|
||||
},
|
||||
clearRateLimited(state, action: PayloadAction<{ sessionId: string }>) {
|
||||
const session = state.sessions[action.payload.sessionId];
|
||||
if (session) session.rate_limited = null;
|
||||
@@ -1489,6 +1510,8 @@ export const {
|
||||
setContextOverflow,
|
||||
setRateLimited,
|
||||
clearRateLimited,
|
||||
setProviderRetrying,
|
||||
clearProviderRetrying,
|
||||
setContextRecovered,
|
||||
clearContextRecovered,
|
||||
setAppDepsChanged,
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
updateSessionContext,
|
||||
setContextOverflow,
|
||||
setRateLimited,
|
||||
setProviderRetrying,
|
||||
setContextRecovered,
|
||||
setAppDepsChanged,
|
||||
setMcpSuggestions,
|
||||
@@ -644,6 +645,17 @@ class WebSocketManager {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'agent:provider_retrying':
|
||||
// Mid-turn CLI backoff: the provider 500/429'd and the CLI is silently waiting; show the muted pill so the card doesn't read as dead (ENG-178).
|
||||
if (session_id) {
|
||||
store.dispatch(setProviderRetrying({
|
||||
sessionId: session_id,
|
||||
attempt: typeof data.attempt === 'number' ? data.attempt : null,
|
||||
delayMs: typeof data.delay_ms === 'number' ? data.delay_ms : null,
|
||||
}));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'agent:rate_limited':
|
||||
// Provider throttle that outlasted the silent backoff. Transient muted pill, not a card; auto-clears frontend-side.
|
||||
if (session_id) {
|
||||
|
||||
Reference in New Issue
Block a user