[Haik]: refactor agents extra reducers to use backend-bridge thunks and fix return types for update_system_prompt, delete_session, stop_agent, switch_branch, and close_session

This commit is contained in:
haikdc
2026-04-18 03:05:44 -07:00
parent bf313d42c2
commit 86a58258ac
2 changed files with 116 additions and 94 deletions
@@ -76,14 +76,14 @@ const update_system_prompt_endpoint: string = `${AGENTS_API}/update_system_promp
async function update_system_prompt_function(payload: {
sessionId: string;
systemPrompt: string;
}): Promise<string> {
}): Promise<{ sessionId: string; systemPrompt: string }> {
const res = await fetch(update_system_prompt_endpoint, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ session_id: payload.sessionId, system_prompt: payload.systemPrompt }),
});
const data = await res.json();
return data.ok as string;
await res.json();
return { sessionId: payload.sessionId, systemPrompt: payload.systemPrompt };
}
export const UPDATE_SYSTEM_PROMPT = createAsyncThunk(
update_system_prompt_endpoint,
@@ -93,14 +93,14 @@ export const UPDATE_SYSTEM_PROMPT = createAsyncThunk(
const delete_session_endpoint: string = `${AGENTS_API}/delete_session`;
async function delete_session_function(sessionId: string): Promise<{ ok: boolean }> {
async function delete_session_function(sessionId: string): Promise<string> {
const res = await fetch(delete_session_endpoint, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ session_id: sessionId }),
});
const data = await res.json();
return data as { ok: boolean };
await res.json();
return sessionId;
}
export const DELETE_SESSION = createAsyncThunk(
delete_session_endpoint,
@@ -155,14 +155,14 @@ export const SEND_MESSAGE = createAsyncThunk(
const stop_agent_endpoint: string = `${AGENTS_API}/stop_agent`;
async function stop_agent_function(sessionId: string): Promise<{ ok: boolean }> {
async function stop_agent_function(sessionId: string): Promise<string> {
const res = await fetch(stop_agent_endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ session_id: sessionId }),
});
const data = await res.json();
return data as { ok: boolean };
await res.json();
return sessionId;
}
export const STOP_AGENT = createAsyncThunk(
stop_agent_endpoint,
@@ -233,14 +233,14 @@ const switch_branch_endpoint: string = `${AGENTS_API}/switch_branch`;
async function switch_branch_function(payload: {
sessionId: string;
branchId: string;
}): Promise<{ ok: boolean }> {
}): Promise<{ sessionId: string; branchId: string }> {
const res = await fetch(switch_branch_endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ session_id: payload.sessionId, branch_id: payload.branchId }),
});
const data = await res.json();
return data as { ok: boolean };
await res.json();
return { sessionId: payload.sessionId, branchId: payload.branchId };
}
export const SWITCH_BRANCH = createAsyncThunk(
switch_branch_endpoint,
@@ -256,14 +256,14 @@ export const SWITCH_BRANCH = createAsyncThunk(
const close_session_endpoint: string = `${AGENTS_API}/close_session`;
async function close_session_function(sessionId: string): Promise<{ ok: boolean }> {
async function close_session_function(sessionId: string): Promise<string> {
const res = await fetch(close_session_endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ session_id: sessionId }),
});
const data = await res.json();
return data as { ok: boolean };
await res.json();
return sessionId;
}
export const CLOSE_SESSION = createAsyncThunk(
close_session_endpoint,
@@ -288,7 +288,7 @@ export const RESUME_SESSION = createAsyncThunk(
);
// NOTE: is a duplicate endpoint even needed? Can't we just do this via branch?
const duplicate_session_endpoint: string = `${AGENTS_API}/duplicate_session`;
async function duplicate_session_function(sessionId: string): Promise<{ session: AgentSession }> {
const res = await fetch(duplicate_session_endpoint, {
+100 -78
View File
@@ -7,13 +7,29 @@ import type { AgentsState, HistorySession } from './agentsTypes';
// closeSession, deleteSession, fetchHistory, resumeSession,
// fetchSession, fetchBrowserAgentChildren, searchHistory,
// } from './agentsThunks';
import {
GET_ALL_SESSIONS,
LAUNCH_AGENT,
UPDATE_SYSTEM_PROMPT,
SEND_MESSAGE,
EDIT_MESSAGE,
STOP_AGENT,
HANDLE_APPROVAL,
SWITCH_BRANCH,
DUPLICATE_SESSION,
CLOSE_SESSION,
DELETE_SESSION,
GET_HISTORY,
RESUME_SESSION,
GET_SESSION,
} from '@/shared/backend-bridge/apps/agents';
export function buildExtraReducers(builder: ActionReducerMapBuilder<AgentsState>) {
builder
.addCase(fetchSessions.pending, (state) => {
.addCase(GET_ALL_SESSIONS.pending, (state) => {
state.loading = true;
})
.addCase(fetchSessions.fulfilled, (state, action) => {
.addCase(GET_ALL_SESSIONS.fulfilled, (state, action) => {
state.loading = false;
const fetchedIds = new Set(action.payload.map((s) => s.id));
const activeStatuses = new Set(['running', 'waiting_approval']);
@@ -39,61 +55,65 @@ export function buildExtraReducers(builder: ActionReducerMapBuilder<AgentsState>
}
}
})
.addCase(fetchSessions.rejected, (state) => {
.addCase(GET_ALL_SESSIONS.rejected, (state) => {
state.loading = false;
})
.addCase(launchAgent.fulfilled, (state, action) => {
state.sessions[action.payload.id] = { ...action.payload, streamingMessage: null, tool_group_meta: action.payload.tool_group_meta ?? {} };
state.activeSessionId = action.payload.id;
if (!state.expandedSessionIds.includes(action.payload.id)) {
state.expandedSessionIds.push(action.payload.id);
}
if (!state.trackedNotificationIds.includes(action.payload.id)) {
state.trackedNotificationIds.push(action.payload.id);
}
})
.addCase(launchAndSendFirstMessage.fulfilled, (state, action) => {
const { draftId, session } = action.payload;
const shouldExpand = action.meta.arg.expand !== false;
delete state.sessions[draftId];
.addCase(LAUNCH_AGENT.fulfilled, (state, action) => {
const session = action.payload.session;
state.sessions[session.id] = { ...session, streamingMessage: null, tool_group_meta: session.tool_group_meta ?? {} };
state.activeSessionId = session.id;
state.expandedSessionIds = state.expandedSessionIds.map((id) => (id === draftId ? session.id : id));
if (shouldExpand && !state.expandedSessionIds.includes(session.id)) {
if (!state.expandedSessionIds.includes(session.id)) {
state.expandedSessionIds.push(session.id);
}
if (!state.trackedNotificationIds.includes(session.id)) {
state.trackedNotificationIds.push(session.id);
}
})
.addCase(generateTitle.fulfilled, (state, action) => {
const session = state.sessions[action.payload.sessionId];
if (session) session.name = action.payload.title;
})
.addCase(generateGroupMeta.fulfilled, (state, action) => {
const session = state.sessions[action.payload.sessionId];
if (session) {
session.tool_group_meta[action.payload.groupId] = {
id: action.payload.groupId,
name: action.payload.name,
svg: action.payload.svg,
is_refined: action.payload.isRefined,
};
}
})
.addCase(updateSystemPrompt.fulfilled, (state, action) => {
// TODO: Re-implement this???
// .addCase(launchAndSendFirstMessage.fulfilled, (state, action) => {
// const { draftId, session } = action.payload;
// const shouldExpand = action.meta.arg.expand !== false;
// delete state.sessions[draftId];
// state.sessions[session.id] = { ...session, streamingMessage: null, tool_group_meta: session.tool_group_meta ?? {} };
// state.activeSessionId = session.id;
// state.expandedSessionIds = state.expandedSessionIds.map((id) => (id === draftId ? session.id : id));
// if (shouldExpand && !state.expandedSessionIds.includes(session.id)) {
// state.expandedSessionIds.push(session.id);
// }
// if (!state.trackedNotificationIds.includes(session.id)) {
// state.trackedNotificationIds.push(session.id);
// }
// })
// TODO: Re-implement this???
// .addCase(generateTitle.fulfilled, (state, action) => {
// const session = state.sessions[action.payload.sessionId];
// if (session) session.name = action.payload.title;
// })
// TODO: Re-implement this???
// .addCase(generateGroupMeta.fulfilled, (state, action) => {
// const session = state.sessions[action.payload.sessionId];
// if (session) {
// session.tool_group_meta[action.payload.groupId] = {
// id: action.payload.groupId,
// name: action.payload.name,
// svg: action.payload.svg,
// is_refined: action.payload.isRefined,
// };
// }
// })
.addCase(UPDATE_SYSTEM_PROMPT.fulfilled, (state, action) => {
const session = state.sessions[action.payload.sessionId];
if (session) session.system_prompt = action.payload.systemPrompt;
})
.addCase(sendMessage.pending, (state, action) => {
.addCase(SEND_MESSAGE.pending, (state, action) => {
const session = state.sessions[action.meta.arg.sessionId];
if (session) session.status = 'running';
})
.addCase(editMessage.pending, (state, action) => {
.addCase(EDIT_MESSAGE.pending, (state, action) => {
const session = state.sessions[action.meta.arg.sessionId];
if (session) session.status = 'running';
})
.addCase(stopAgent.fulfilled, (state, action) => {
.addCase(STOP_AGENT.fulfilled, (state, action) => {
const session = state.sessions[action.payload];
if (session) {
session.status = 'stopped';
@@ -101,24 +121,25 @@ export function buildExtraReducers(builder: ActionReducerMapBuilder<AgentsState>
session.pending_approvals = [];
}
})
.addCase(handleApproval.fulfilled, (state, action) => {
.addCase(HANDLE_APPROVAL.fulfilled, (state, action) => {
for (const session of Object.values(state.sessions)) {
session.pending_approvals = session.pending_approvals.filter(
(r) => r.id !== action.payload.requestId
);
}
})
.addCase(handleApproval.rejected, (_state, action) => {
.addCase(HANDLE_APPROVAL.rejected, (_state, action) => {
console.error('Approval request failed:', action.error.message);
})
.addCase(switchBranch.fulfilled, (state, action) => {
.addCase(SWITCH_BRANCH.fulfilled, (state, action) => {
const session = state.sessions[action.payload.sessionId];
if (session) session.active_branch_id = action.payload.branchId;
})
.addCase(duplicateSession.fulfilled, (state, action) => {
state.sessions[action.payload.id] = action.payload;
.addCase(DUPLICATE_SESSION.fulfilled, (state, action) => {
const session = action.payload.session;
state.sessions[session.id] = session;
})
.addCase(closeSession.fulfilled, (state, action) => {
.addCase(CLOSE_SESSION.fulfilled, (state, action) => {
const sessionId = action.payload;
const session = state.sessions[sessionId];
if (session) {
@@ -134,8 +155,8 @@ export function buildExtraReducers(builder: ActionReducerMapBuilder<AgentsState>
state.expandedSessionIds = state.expandedSessionIds.filter((id) => id !== sessionId);
state.trackedNotificationIds = state.trackedNotificationIds.filter((id) => id !== sessionId);
})
.addCase(closeSession.rejected, (state, action) => {
const sessionId = action.meta.arg.sessionId;
.addCase(CLOSE_SESSION.rejected, (state, action) => {
const sessionId = action.meta.arg;
const session = state.sessions[sessionId];
if (session) {
state.history[sessionId] = {
@@ -150,7 +171,7 @@ export function buildExtraReducers(builder: ActionReducerMapBuilder<AgentsState>
state.expandedSessionIds = state.expandedSessionIds.filter((id) => id !== sessionId);
state.trackedNotificationIds = state.trackedNotificationIds.filter((id) => id !== sessionId);
})
.addCase(deleteSession.fulfilled, (state, action) => {
.addCase(DELETE_SESSION.fulfilled, (state, action) => {
const sessionId = action.payload;
delete state.history[sessionId];
delete state.sessions[sessionId];
@@ -158,19 +179,19 @@ export function buildExtraReducers(builder: ActionReducerMapBuilder<AgentsState>
state.expandedSessionIds = state.expandedSessionIds.filter((id) => id !== sessionId);
state.trackedNotificationIds = state.trackedNotificationIds.filter((id) => id !== sessionId);
})
.addCase(fetchHistory.fulfilled, (state, action) => {
.addCase(GET_HISTORY.fulfilled, (state, action) => {
const history: Record<string, HistorySession> = {};
for (const s of action.payload) history[s.id] = s;
for (const s of action.payload.sessions) history[s.id] = s;
state.history = history;
})
.addCase(resumeSession.fulfilled, (state, action) => {
.addCase(RESUME_SESSION.fulfilled, (state, action) => {
const session = action.payload;
state.sessions[session.id] = { ...session, streamingMessage: null, tool_group_meta: session.tool_group_meta ?? {} };
delete state.history[session.id];
state.activeSessionId = session.id;
if (!state.expandedSessionIds.includes(session.id)) state.expandedSessionIds.push(session.id);
})
.addCase(fetchSession.fulfilled, (state, action) => {
.addCase(GET_SESSION.fulfilled, (state, action) => {
const session = action.payload;
const existing = state.sessions[session.id];
state.sessions[session.id] = {
@@ -180,31 +201,32 @@ export function buildExtraReducers(builder: ActionReducerMapBuilder<AgentsState>
tool_group_meta: session.tool_group_meta ?? existing?.tool_group_meta ?? {},
};
})
.addCase(fetchBrowserAgentChildren.fulfilled, (state, action) => {
for (const session of action.payload) {
if (!state.sessions[session.id]) {
state.sessions[session.id] = {
...session, streamingMessage: null, tool_group_meta: session.tool_group_meta ?? {},
};
}
}
})
.addCase(searchHistory.pending, (state) => {
state.historySearch.loading = true;
})
.addCase(searchHistory.fulfilled, (state, action) => {
const { sessions, total, hasMore, query, offset } = action.payload;
if (offset === 0) {
state.historySearch.results = sessions;
} else {
state.historySearch.results = [...state.historySearch.results, ...sessions];
}
state.historySearch.total = total;
state.historySearch.hasMore = hasMore;
state.historySearch.query = query;
state.historySearch.loading = false;
})
.addCase(searchHistory.rejected, (state) => {
state.historySearch.loading = false;
});
// TODO: Re-implement this???
// .addCase(fetchBrowserAgentChildren.fulfilled, (state, action) => {
// for (const session of action.payload) {
// if (!state.sessions[session.id]) {
// state.sessions[session.id] = {
// ...session, streamingMessage: null, tool_group_meta: session.tool_group_meta ?? {},
// };
// }
// }
// })
// .addCase(searchHistory.pending, (state) => {
// state.historySearch.loading = true;
// })
// .addCase(searchHistory.fulfilled, (state, action) => {
// const { sessions, total, hasMore, query, offset } = action.payload;
// if (offset === 0) {
// state.historySearch.results = sessions;
// } else {
// state.historySearch.results = [...state.historySearch.results, ...sessions];
// }
// state.historySearch.total = total;
// state.historySearch.hasMore = hasMore;
// state.historySearch.query = query;
// state.historySearch.loading = false;
// })
// .addCase(searchHistory.rejected, (state) => {
// state.historySearch.loading = false;
// });
}