Fix 'Edit In Place' and 'Fork Session' features (#6970)

Signed-off-by: Bright Zheng <bright@squareup.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Zane Staggs <zane@squareup.com>
This commit is contained in:
Bright Zheng
2026-02-09 17:29:34 -05:00
committed by GitHub
parent 5b15593e0a
commit 17dff138cc
4 changed files with 39 additions and 53 deletions
+1 -1
View File
@@ -593,7 +593,7 @@ export function AppInner() {
console.log('[App] Processing initial message from launcher:', initialMessage); console.log('[App] Processing initial message from launcher:', initialMessage);
navigate('/pair', { navigate('/pair', {
state: { state: {
initialMessage, initialMessage: { msg: initialMessage, images: [] },
}, },
}); });
setTimeout(() => { setTimeout(() => {
+1 -1
View File
@@ -279,7 +279,7 @@ export default function BaseChat({
navigate(`/pair?${params.toString()}`, { navigate(`/pair?${params.toString()}`, {
state: { state: {
disableAnimation: true, disableAnimation: true,
initialMessage: editedMessage, initialMessage: editedMessage ? { msg: editedMessage, images: [] } : undefined,
}, },
}); });
}; };
+6 -3
View File
@@ -76,9 +76,12 @@ export function useAutoSubmit({
// Scenario 2: Forked session with edited message // Scenario 2: Forked session with edited message
if (shouldStartAgent && initialMessage) { if (shouldStartAgent && initialMessage) {
hasAutoSubmittedRef.current = true; if (messages.length > 0) {
handleSubmit(initialMessage); hasAutoSubmittedRef.current = true;
clearInitialMessage(); handleSubmit(initialMessage);
clearInitialMessage();
return;
}
return; return;
} }
+31 -48
View File
@@ -369,9 +369,6 @@ export function useChatStream({
const isNewSession = sessionId && sessionId.match(/^\d{8}_\d{6}$/); const isNewSession = sessionId && sessionId.match(/^\d{8}_\d{6}$/);
if (isNewSession) { if (isNewSession) {
console.log(
'useChatStream: Message stream finished for new session, emitting message-stream-finished event'
);
window.dispatchEvent(new CustomEvent(AppEvents.MESSAGE_STREAM_FINISHED)); window.dispatchEvent(new CustomEvent(AppEvents.MESSAGE_STREAM_FINISHED));
} }
@@ -591,6 +588,7 @@ export function useChatStream({
body: { body: {
session_id: sessionId, session_id: sessionId,
user_message: newMessage, user_message: newMessage,
...(hasExistingMessages && { conversation_so_far: currentState.messages }),
}, },
throwOnError: true, throwOnError: true,
signal: abortControllerRef.current.signal, signal: abortControllerRef.current.signal,
@@ -751,55 +749,40 @@ export function useChatStream({
}); });
if (sessionResponse.data?.conversation) { if (sessionResponse.data?.conversation) {
const updatedMessages = [...sessionResponse.data.conversation]; const truncatedMessages = [...sessionResponse.data.conversation];
const updatedUserMessage = createUserMessage(newContent);
if (updatedMessages.length > 0) { for (const content of message.content) {
const lastMessage = updatedMessages[updatedMessages.length - 1]; if (content.type === 'image') {
if (lastMessage.role === 'user') { updatedUserMessage.content.push(content);
lastMessage.content = [{ type: 'text', text: newContent }];
for (const content of message.content) {
if (content.type === 'image') {
lastMessage.content.push(content);
}
}
dispatch({ type: 'SET_MESSAGES', payload: updatedMessages });
dispatch({ type: 'START_STREAMING' });
abortControllerRef.current = new AbortController();
try {
const placeholderMessage = createUserMessage(newContent);
const { stream } = await reply({
body: {
session_id: targetSessionId,
user_message: placeholderMessage,
},
throwOnError: true,
signal: abortControllerRef.current.signal,
});
await streamFromResponse(
stream,
updatedMessages,
dispatch,
onFinish,
targetSessionId
);
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
dispatch({ type: 'SET_CHAT_STATE', payload: ChatState.Idle });
} else {
throw error;
}
}
return;
} }
} }
dispatch({ type: 'SET_MESSAGES', payload: sessionResponse.data.conversation }); const messagesForUI = [...truncatedMessages, updatedUserMessage];
await handleSubmit({ msg: newContent, images: [] }); dispatch({ type: 'SET_MESSAGES', payload: messagesForUI });
dispatch({ type: 'START_STREAMING' });
abortControllerRef.current = new AbortController();
try {
const { stream } = await reply({
body: {
session_id: targetSessionId,
user_message: updatedUserMessage,
conversation_so_far: truncatedMessages,
},
throwOnError: true,
signal: abortControllerRef.current.signal,
});
await streamFromResponse(stream, messagesForUI, dispatch, onFinish, targetSessionId);
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
dispatch({ type: 'SET_CHAT_STATE', payload: ChatState.Idle });
} else {
throw error;
}
}
} else { } else {
await handleSubmit({ msg: newContent, images: [] }); await handleSubmit({ msg: newContent, images: [] });
} }