Skip to content

Commit 7587c2b

Browse files
committed
wip(chore-db): branching user messages.
1 parent dc15367 commit 7587c2b

File tree

1 file changed

+81
-63
lines changed

1 file changed

+81
-63
lines changed

refact-agent/gui/src/components/MessageNode/MessageNode.tsx

Lines changed: 81 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import React, { useEffect, useMemo } from "react";
1+
import React, { useCallback, useEffect, useMemo } from "react";
22
import {
33
chatDbMessageSliceActions,
44
CMessageNode,
55
isUserCMessageNode,
6-
UserCMessageNode,
76
} from "../../features/ChatDB/chatDbMessagesSlice";
87
import { UserInput } from "../ChatContent/UserInput";
98
import { AssistantInput } from "../ChatContent/AssistantInput";
@@ -15,7 +14,7 @@ import {
1514
isPlainTextMessage,
1615
isUserMessage,
1716
} from "../../services/refact";
18-
import { IconButton } from "@radix-ui/themes";
17+
import { Box, Flex, IconButton } from "@radix-ui/themes";
1918
import { ArrowLeftIcon, ArrowRightIcon } from "@radix-ui/react-icons";
2019
import { PlainText } from "../ChatContent/PlainText";
2120
import { ContextFiles } from "../ChatContent/ContextFiles";
@@ -87,74 +86,93 @@ export const MessageNode: React.FC<MessageNodeProps> = ({ children }) => {
8786
);
8887
};
8988

89+
function makeDummyNode(lastMessage?: CMessageNode): CMessageNode {
90+
return {
91+
message: {
92+
cmessage_usage_model: lastMessage?.message.cmessage_usage_model ?? "",
93+
cmessage_usage_prompt: lastMessage?.message.cmessage_usage_prompt ?? 0,
94+
cmessage_usage_completion:
95+
lastMessage?.message.cmessage_usage_completion ?? 0,
96+
cmessage_belongs_to_cthread_id:
97+
lastMessage?.message.cmessage_belongs_to_cthread_id ?? "",
98+
cmessage_num: lastMessage?.message.cmessage_num ?? 0,
99+
100+
cmessage_alt: (lastMessage?.message.cmessage_alt ?? 0) + 1,
101+
cmessage_prev_alt: lastMessage?.message.cmessage_alt ?? 0,
102+
cmessage_json: {
103+
role: "user",
104+
content: "dummy text about making a new message",
105+
}, // TODO: use a different type of message
106+
},
107+
children: [],
108+
};
109+
}
110+
90111
const MessageNodeChildren: React.FC<{ children: CMessageNode[] }> = ({
91112
children,
92113
}) => {
93-
const userMessages: UserCMessageNode[] = children.filter(isUserCMessageNode);
114+
const [selectedNodeIndex, setSelectedNodeIndex] = React.useState<number>(0);
94115

95-
if (userMessages.length === 0) {
96-
return children.map((node, index) => {
97-
const key = `${node.message.cmessage_belongs_to_cthread_id}_${node.message.cmessage_num}_${node.message.cmessage_alt}_${index}`;
98-
return <MessageNode key={key}>{node}</MessageNode>;
116+
const goBack = useCallback(() => {
117+
setSelectedNodeIndex((prev) => {
118+
if (prev === 0) return prev;
119+
return prev - 1;
99120
});
100-
} else {
101-
return <UserMessageNode>{userMessages}</UserMessageNode>;
102-
}
103-
};
121+
}, []);
104122

105-
const UserMessageNode: React.FC<{ children: UserCMessageNode[] }> = ({
106-
children,
107-
}) => {
108-
// info about the node may need to be shared with the user input
109-
const dispatch = useAppDispatch();
110-
const [selectedNodeIndex, setSelectedNodeIndex] = React.useState<number>(0);
111-
112-
const selectedNode = children[selectedNodeIndex];
123+
const goForward = useCallback(() => {
124+
setSelectedNodeIndex((prev) => {
125+
if (prev === children.length) return prev;
126+
return prev + 1;
127+
});
128+
}, [children.length]);
113129

114-
useEffect(() => {
115-
if (selectedNode.children.length === 0) {
116-
const action = chatDbMessageSliceActions.setEnd({
117-
number: selectedNode.message.cmessage_num,
118-
alt: selectedNode.message.cmessage_alt,
119-
});
120-
dispatch(action);
130+
const canBranch = useMemo(() => {
131+
if (children.length > 1) return true;
132+
if (selectedNodeIndex >= children.length && selectedNodeIndex > 0) {
133+
return true;
121134
}
122-
}, [
123-
selectedNode.children.length,
124-
selectedNode.message.cmessage_num,
125-
selectedNode.message.cmessage_alt,
126-
dispatch,
127-
]);
135+
if (
136+
children[selectedNodeIndex] &&
137+
isUserCMessageNode(children[selectedNodeIndex])
138+
) {
139+
return true;
140+
}
141+
return false;
142+
}, [children, selectedNodeIndex]);
143+
144+
const nodeToRender = useMemo(() => {
145+
return (
146+
children[selectedNodeIndex] ??
147+
makeDummyNode(children[children.length - 1])
148+
);
149+
}, [children, selectedNodeIndex]);
150+
151+
if (!canBranch) {
152+
return <MessageNode>{children[selectedNodeIndex]}</MessageNode>;
153+
}
154+
128155
return (
129-
<>
130-
<IconButton
131-
variant="outline"
132-
size="1"
133-
disabled={selectedNodeIndex === 0}
134-
onClick={() =>
135-
setSelectedNodeIndex((prev) => {
136-
if (prev === 0) return prev;
137-
return prev - 1;
138-
})
139-
}
140-
>
141-
<ArrowLeftIcon />
142-
</IconButton>
143-
<IconButton
144-
variant="outline"
145-
size="1"
146-
disabled={selectedNodeIndex === children.length - 1}
147-
onClick={() => {
148-
setSelectedNodeIndex((prev) => {
149-
if (prev === children.length - 1) return prev;
150-
return prev + 1;
151-
});
152-
}}
153-
>
154-
<ArrowRightIcon />
155-
</IconButton>
156-
<UserInput>{selectedNode.message.cmessage_json.content}</UserInput>
157-
<MessageNodeChildren>{selectedNode.children}</MessageNodeChildren>
158-
</>
156+
<Box>
157+
<Flex gap="4" justify="end">
158+
<IconButton
159+
variant="outline"
160+
size="1"
161+
disabled={selectedNodeIndex === 0}
162+
onClick={goBack}
163+
>
164+
<ArrowLeftIcon />
165+
</IconButton>
166+
<IconButton
167+
variant="outline"
168+
size="1"
169+
disabled={selectedNodeIndex === children.length}
170+
onClick={goForward}
171+
>
172+
<ArrowRightIcon />
173+
</IconButton>
174+
</Flex>
175+
<MessageNode>{nodeToRender}</MessageNode>
176+
</Box>
159177
);
160178
};

0 commit comments

Comments
 (0)