Skip to content

Commit cb56432

Browse files
MarcMcIntosholegklimov
authored andcommitted
fix(acceot / reject): prevent sending message no rejection.
1 parent 36c5bcf commit cb56432

File tree

4 files changed

+105
-86
lines changed

4 files changed

+105
-86
lines changed

refact-agent/gui/src/app/middleware.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
newIntegrationChat,
1313
chatResponse,
1414
setIsWaitingForResponse,
15+
upsertToolCall,
1516
} from "../features/Chat/Thread";
1617
import { statisticsApi } from "../services/refact/statistics";
1718
import { integrationsApi } from "../services/refact/integrations";
@@ -46,6 +47,7 @@ import {
4647
updateMaxAgentUsageAmount,
4748
} from "../features/AgentUsage/agentUsageSlice";
4849
import { ideToolCallResponse } from "../hooks/useEventBusForIDE";
50+
import { upsertToolCallIntoHistory } from "../features/History/historySlice";
4951

5052
const AUTH_ERROR_MESSAGE =
5153
"There is an issue with your API key. Check out your API Key or re-login";
@@ -508,6 +510,12 @@ startListening({
508510
actionCreator: ideToolCallResponse,
509511
effect: (action, listenerApi) => {
510512
const state = listenerApi.getState();
513+
514+
// TODO: also handle this in confirmation box
515+
if (action.payload.accepted === false) {
516+
listenerApi.dispatch(upsertToolCallIntoHistory(action.payload));
517+
listenerApi.dispatch(upsertToolCall(action.payload));
518+
}
511519
listenerApi.dispatch(updateConfirmationAfterIdeToolUse(action.payload));
512520

513521
const pauseReasons = state.confirmation.pauseReasons.filter(
@@ -516,6 +524,7 @@ startListening({
516524

517525
if (pauseReasons.length === 0) {
518526
// TODO: it seems odd tool confirmation opens with no reasons.
527+
// changin pause should remove it too.
519528
listenerApi.dispatch(
520529
clearPauseReasonsAndHandleToolsStatus({
521530
wasInteracted: true, // bit of a work around to enable auto send again.

refact-agent/gui/src/features/Chat/Thread/actions.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import { ToolCommand } from "../../../services/refact/tools";
3434
import { scanFoDuplicatesWith, takeFromEndWhile } from "../../../utils";
3535
import { debugApp } from "../../../debugConfig";
3636
import { ChatHistoryItem } from "../../History/historySlice";
37+
import { ideToolCallResponse } from "../../../hooks/useEventBusForIDE";
3738

3839
export const newChatAction = createAction("chatThread/new");
3940

@@ -144,9 +145,9 @@ export const fixBrokenToolMessages = createAction<PayloadWithId>(
144145
"chatThread/fixBrokenToolMessages",
145146
);
146147

147-
// export const upsertToolCall = createAction<
148-
// Parameters<typeof ideToolCallResponse>[0]
149-
// >("chatThread/upsertToolCall");
148+
export const upsertToolCall = createAction<
149+
Parameters<typeof ideToolCallResponse>[0]
150+
>("chatThread/upsertToolCall");
150151

151152
// TODO: This is the circular dep when imported from hooks :/
152153
const createAppAsyncThunk = createAsyncThunk.withTypes<{

refact-agent/gui/src/features/Chat/Thread/reducer.ts

Lines changed: 78 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createReducer } from "@reduxjs/toolkit";
1+
import { createReducer, Draft } from "@reduxjs/toolkit";
22
import {
33
Chat,
44
ChatThread,
@@ -38,8 +38,14 @@ import {
3838
} from "./actions";
3939
import { formatChatResponse } from "./utils";
4040
import {
41+
ChatMessages,
4142
DEFAULT_MAX_NEW_TOKENS,
43+
isAssistantMessage,
44+
isDiffMessage,
45+
isMultiModalToolResult,
4246
isToolCallMessage,
47+
isToolMessage,
48+
ToolMessage,
4349
validateToolCall,
4450
} from "../../../services/refact";
4551

@@ -335,76 +341,76 @@ export const chatReducer = createReducer(initialState, (builder) => {
335341
state.thread.messages = [...messages, newMessage];
336342
});
337343

338-
// builder.addCase(upsertToolCall, (state, action) => {
339-
// // if (action.payload.toolCallId !== state.thread.id && !(action.payload.chatId in state.cache)) return state;
340-
// if (action.payload.chatId === state.thread.id) {
341-
// maybeAppendToolCallResultFromIdeToMessages(
342-
// state.thread.messages,
343-
// action.payload.toolCallId,
344-
// action.payload.accepted,
345-
// );
346-
// } else if (action.payload.chatId in state.cache) {
347-
// const thread = state.cache[action.payload.chatId];
348-
// maybeAppendToolCallResultFromIdeToMessages(
349-
// thread.messages,
350-
// action.payload.toolCallId,
351-
// action.payload.accepted,
352-
// );
353-
// }
354-
// });
344+
builder.addCase(upsertToolCall, (state, action) => {
345+
// if (action.payload.toolCallId !== state.thread.id && !(action.payload.chatId in state.cache)) return state;
346+
if (action.payload.chatId === state.thread.id) {
347+
maybeAppendToolCallResultFromIdeToMessages(
348+
state.thread.messages,
349+
action.payload.toolCallId,
350+
action.payload.accepted,
351+
);
352+
} else if (action.payload.chatId in state.cache) {
353+
const thread = state.cache[action.payload.chatId];
354+
maybeAppendToolCallResultFromIdeToMessages(
355+
thread.messages,
356+
action.payload.toolCallId,
357+
action.payload.accepted,
358+
);
359+
}
360+
});
355361
});
356362

357-
// export function maybeAppendToolCallResultFromIdeToMessages(
358-
// messages: Draft<ChatMessages>,
359-
// toolCallId: string,
360-
// accepted: boolean | "indeterminate",
361-
// ) {
362-
// const hasDiff = messages.find(
363-
// (d) => isDiffMessage(d) && d.tool_call_id === toolCallId,
364-
// );
365-
// if (hasDiff) return;
366-
367-
// const message = messageForToolCall(accepted);
368-
369-
// const hasToolCall = messages.find(
370-
// (d) => isToolMessage(d) && d.content.tool_call_id === toolCallId,
371-
// );
372-
373-
// if (
374-
// hasToolCall &&
375-
// isToolMessage(hasToolCall) &&
376-
// typeof hasToolCall.content.content === "string"
377-
// ) {
378-
// hasToolCall.content.content = message;
379-
// return;
380-
// } else if (
381-
// hasToolCall &&
382-
// isToolMessage(hasToolCall) &&
383-
// isMultiModalToolResult(hasToolCall.content)
384-
// ) {
385-
// hasToolCall.content.content.push({ m_type: "text", m_content: message });
386-
// return;
387-
// }
388-
389-
// const assistantMessageIndex = messages.findIndex((message) => {
390-
// if (!isAssistantMessage(message)) return false;
391-
// return message.tool_calls?.find((toolCall) => toolCall.id === toolCallId);
392-
// });
393-
394-
// if (assistantMessageIndex === -1) return;
395-
// const toolMessage: ToolMessage = {
396-
// role: "tool",
397-
// content: {
398-
// content: message,
399-
// tool_call_id: toolCallId,
400-
// },
401-
// };
402-
403-
// messages.splice(assistantMessageIndex + 1, 0, toolMessage);
404-
// }
405-
406-
// function messageForToolCall(accepted: boolean | "indeterminate") {
407-
// if (accepted === false) return "The user rejected the changes.";
408-
// if (accepted === true) return "The user accepted the changes.";
409-
// return "The user may have made modifications to changes.";
410-
// }
363+
export function maybeAppendToolCallResultFromIdeToMessages(
364+
messages: Draft<ChatMessages>,
365+
toolCallId: string,
366+
accepted: boolean | "indeterminate",
367+
) {
368+
const hasDiff = messages.find(
369+
(d) => isDiffMessage(d) && d.tool_call_id === toolCallId,
370+
);
371+
if (hasDiff) return;
372+
373+
const message = messageForToolCall(accepted);
374+
375+
const hasToolCall = messages.find(
376+
(d) => isToolMessage(d) && d.content.tool_call_id === toolCallId,
377+
);
378+
379+
if (
380+
hasToolCall &&
381+
isToolMessage(hasToolCall) &&
382+
typeof hasToolCall.content.content === "string"
383+
) {
384+
hasToolCall.content.content = message;
385+
return;
386+
} else if (
387+
hasToolCall &&
388+
isToolMessage(hasToolCall) &&
389+
isMultiModalToolResult(hasToolCall.content)
390+
) {
391+
hasToolCall.content.content.push({ m_type: "text", m_content: message });
392+
return;
393+
}
394+
395+
const assistantMessageIndex = messages.findIndex((message) => {
396+
if (!isAssistantMessage(message)) return false;
397+
return message.tool_calls?.find((toolCall) => toolCall.id === toolCallId);
398+
});
399+
400+
if (assistantMessageIndex === -1) return;
401+
const toolMessage: ToolMessage = {
402+
role: "tool",
403+
content: {
404+
content: message,
405+
tool_call_id: toolCallId,
406+
},
407+
};
408+
409+
messages.splice(assistantMessageIndex + 1, 0, toolMessage);
410+
}
411+
412+
function messageForToolCall(accepted: boolean | "indeterminate") {
413+
if (accepted === false) return "The user rejected the changes.";
414+
if (accepted === true) return "The user accepted the changes.";
415+
return "The user may have made modifications to changes.";
416+
}

refact-agent/gui/src/features/History/historySlice.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
chatGenerateTitleThunk,
1010
ChatThread,
1111
doneStreaming,
12+
maybeAppendToolCallResultFromIdeToMessages,
1213
removeChatFromCache,
1314
restoreChat,
1415
setChatMode,
@@ -20,6 +21,7 @@ import {
2021
isUserMessage,
2122
} from "../../services/refact";
2223
import { AppDispatch, RootState } from "../../app/store";
24+
import { ideToolCallResponse } from "../../hooks/useEventBusForIDE";
2325

2426
export type ChatHistoryItem = Omit<ChatThread, "new_chat_suggested"> & {
2527
createdAt: string;
@@ -144,17 +146,17 @@ export const historySlice = createSlice({
144146
return {};
145147
},
146148

147-
// upsertToolCallIntoHistory: (
148-
// state,
149-
// action: PayloadAction<Parameters<typeof ideToolCallResponse>[0]>,
150-
// ) => {
151-
// if (!(action.payload.chatId in state)) return;
152-
// maybeAppendToolCallResultFromIdeToMessages(
153-
// state[action.payload.chatId].messages,
154-
// action.payload.toolCallId,
155-
// action.payload.accepted,
156-
// );
157-
// },
149+
upsertToolCallIntoHistory: (
150+
state,
151+
action: PayloadAction<Parameters<typeof ideToolCallResponse>[0]>,
152+
) => {
153+
if (!(action.payload.chatId in state)) return;
154+
maybeAppendToolCallResultFromIdeToMessages(
155+
state[action.payload.chatId].messages,
156+
action.payload.toolCallId,
157+
action.payload.accepted,
158+
);
159+
},
158160
},
159161
selectors: {
160162
getChatById: (state, id: string): ChatHistoryItem | null => {
@@ -177,6 +179,7 @@ export const {
177179
setTitleGenerationCompletionForChat,
178180
updateChatTitleById,
179181
clearHistory,
182+
upsertToolCallIntoHistory,
180183
} = historySlice.actions;
181184
export const { getChatById, getHistory } = historySlice.selectors;
182185

0 commit comments

Comments
 (0)