View model interactions (#9806)

Signed-off-by: Douwe M Osinga <douwe@sidewalklabs.com>
Co-authored-by: Douwe M Osinga <douwe@sidewalklabs.com>
Co-authored-by: Michael Neale <michael.neale@gmail.com>
This commit is contained in:
Douwe Osinga
2026-06-18 20:28:03 -04:00
committed by GitHub
parent 09c8d2be5a
commit 08fb6d45f3
18 changed files with 676 additions and 116 deletions
+22 -4
View File
@@ -192,8 +192,8 @@ export function useAcpChatSession({
useEffect(() => {
const handleSessionRenamed = (event: Event) => {
const { sessionId: renamedSessionId, newName } = (
event as CustomEvent<{ sessionId: string; newName: string }>
const { sessionId: renamedSessionId, newName, userInitiated } = (
event as CustomEvent<{ sessionId: string; newName: string; userInitiated?: boolean }>
).detail;
if (renamedSessionId !== sessionId) {
@@ -201,11 +201,15 @@ export function useAcpChatSession({
}
const currentSession = stateRef.current.session;
if (!currentSession || currentSession.name === newName) {
if (!currentSession || (currentSession.name === newName && !userInitiated)) {
return;
}
const updatedSession = { ...currentSession, name: newName };
const updatedSession = {
...currentSession,
name: newName,
...(userInitiated && { user_set_name: true }),
};
acpChatSessionStore.setSessionMetadata(sessionId, updatedSession);
dispatch({ type: 'SET_SESSION', payload: updatedSession });
};
@@ -567,6 +571,19 @@ export function useAcpChatSession({
[sessionId]
);
const updateSession = useCallback(
(updater: (session: Session) => Session) => {
const cached = acpChatSessionStore.getSnapshot(sessionId);
const currentSession = stateRef.current.session ?? cached?.session;
if (!currentSession) return;
const nextSession = updater(currentSession);
acpChatSessionStore.setSessionMetadata(sessionId, nextSession);
dispatch({ type: 'SET_SESSION', payload: nextSession });
},
[sessionId]
);
const cached = acpChatSessionStore.getSnapshot(sessionId);
const maybe_cached_messages = state.session ? state.messages : cached?.messages || [];
const maybe_cached_session = state.session ?? cached?.session;
@@ -588,6 +605,7 @@ export function useAcpChatSession({
session: maybe_cached_session,
chatState: state.chatState,
setChatState,
updateSession,
handleSubmit,
submitElicitationResponse,
stopStreaming,
@@ -13,6 +13,7 @@ export interface UseChatSessionResult {
messages: Message[];
chatState: ChatState;
setChatState: (state: ChatState) => void;
updateSession: (updater: (session: Session) => Session) => void;
handleSubmit: (input: UserInput) => Promise<void>;
submitElicitationResponse: (
elicitationId: string,
+45 -9
View File
@@ -476,10 +476,16 @@ export function useChatStream({
throwOnError: true,
});
if (response.data?.name) {
const nextMessageCount =
response.data.message_count ?? currentState.session?.message_count;
dispatch({
type: 'SET_SESSION',
payload: currentState.session
? { ...currentState.session, name: response.data.name }
? {
...currentState.session,
name: response.data.name,
...(nextMessageCount !== undefined && { message_count: nextMessageCount }),
}
: undefined,
});
window.dispatchEvent(
@@ -873,21 +879,32 @@ export function useChatStream({
});
const currentState = stateRef.current;
const currentName = currentState.session?.name;
const currentMessageCount = currentState.session?.message_count;
const newName = response.data?.name;
const newMessageCount = response.data?.message_count;
const hasNameChange = Boolean(newName && newName !== currentName);
const hasMessageCountChange =
newMessageCount !== undefined && newMessageCount !== currentMessageCount;
if (newName && newName !== currentName) {
if (newName && (hasNameChange || hasMessageCountChange)) {
dispatch({
type: 'SET_SESSION',
payload: currentState.session
? { ...currentState.session, name: newName }
? {
...currentState.session,
name: newName,
...(newMessageCount !== undefined && { message_count: newMessageCount }),
}
: undefined,
});
window.dispatchEvent(
new CustomEvent(AppEvents.SESSION_RENAMED, {
detail: { sessionId, newName },
})
);
return;
if (hasNameChange) {
window.dispatchEvent(
new CustomEvent(AppEvents.SESSION_RENAMED, {
detail: { sessionId, newName },
})
);
return;
}
}
} catch {
// Silently continue polling
@@ -1116,6 +1133,24 @@ export function useChatStream({
dispatch({ type: 'SET_CHAT_STATE', payload: newState });
}, []);
const updateSession = useCallback(
(updater: (session: Session) => Session) => {
const cached = resultsCache.get(sessionId);
const currentSession = stateRef.current.session ?? cached?.session;
if (!currentSession) return;
const nextSession = updater(currentSession);
dispatch({ type: 'SET_SESSION', payload: nextSession });
resultsCache.set(sessionId, {
session: nextSession,
messages: stateRef.current.messages.length
? stateRef.current.messages
: cached?.messages || [],
});
},
[sessionId]
);
const cached = resultsCache.get(sessionId);
const maybe_cached_messages = state.session ? state.messages : cached?.messages || [];
const maybe_cached_session = state.session ?? cached?.session;
@@ -1137,6 +1172,7 @@ export function useChatStream({
session: maybe_cached_session,
chatState: state.chatState,
setChatState,
updateSession,
handleSubmit,
submitElicitationResponse,
stopStreaming,