Skip to content

Commit 96be369

Browse files
committed
wip(chat db): create thread, subscribe and send messages.
1 parent 73f8ac1 commit 96be369

File tree

7 files changed

+107
-83
lines changed

7 files changed

+107
-83
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ function useGetHistory() {
3838
const thunk = dispatch(subscribeToThreadsThunk());
3939
return () => {
4040
try {
41+
thunk.catch(() => ({}));
4142
thunk.abort("unmounted");
4243
} catch {
4344
// noop

refact-agent/gui/src/features/ChatDB/chatDbMessagesSlice.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
22
import {
33
CMessageFromChatDB,
44
CThread,
5-
CThreadDefault,
65
CMessage,
76
ChatMessage,
87
UserCMessage,
98
isUserCMessage,
109
} from "../../services/refact";
11-
import { v4 as uuid } from "uuid";
1210
import { parseOrElse } from "../../utils";
1311
import { makeMessageTree } from "./makeMessageTree";
1412
import { pagesSlice } from "../Pages/pagesSlice";
@@ -31,22 +29,20 @@ export function isUserCMessageNode(
3129
}
3230

3331
type InitialState = {
34-
thread: CThread | CThreadDefault;
32+
thread: Pick<CThread, "cthread_id" | "cthread_model" | "cthread_toolset">;
3533
messageList: CMessage[];
3634
loading: boolean;
3735
error: null | string;
3836
endNumber: number;
3937
endAlt: number;
4038
};
4139

42-
const createChatThread = (): CThreadDefault => {
43-
const thread: CThreadDefault = {
44-
cthread_id: uuid(),
45-
cthread_title: "",
40+
const createChatThread = (): InitialState["thread"] => {
41+
const thread = {
42+
cthread_id: "",
4643
cthread_toolset: "",
4744
cthread_model: "",
4845
};
49-
5046
return thread;
5147
};
5248

@@ -75,7 +71,7 @@ export const chatDbMessageSlice = createSlice({
7571
name: "chatDbMessages",
7672
initialState,
7773
reducers: {
78-
setThread: (state, action: PayloadAction<CThread>) => {
74+
setThread: (state, action: PayloadAction<InitialState["thread"]>) => {
7975
state.thread = action.payload;
8076
},
8177
updateMessage: (
@@ -114,17 +110,17 @@ export const chatDbMessageSlice = createSlice({
114110
builder.addMatcher(pagesSlice.actions.push.match, (state, action) => {
115111
if (action.payload.name !== "chat") return state;
116112
if (action.payload.threadId !== undefined) return state;
117-
// TODO: other data passed from previouly used chat.
118113
const thread = createChatThread();
119114
thread.cthread_model = state.thread.cthread_model;
120115
thread.cthread_toolset = state.thread.cthread_toolset;
121-
state = { ...initialState, thread };
116+
return { ...initialState, thread };
122117
});
123118
},
124119

125120
selectors: {
126121
selectMessageTree: (state) => makeMessageTree(state.messageList),
127122
selectThread: (state) => state.thread,
123+
selectThreadId: (state) => state.thread.cthread_id,
128124
selectLeafEndPosition: (state) => ({
129125
num: state.endNumber,
130126
alt: state.endAlt,

refact-agent/gui/src/hooks/useThreadMessageSubmit.ts

Lines changed: 55 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,83 @@
11
import { useCallback, useMemo } from "react";
2+
import { v4 as uuidv4 } from "uuid";
23
import { useAppSelector } from "./useAppSelector";
3-
import { chatDbMessagesSliceSelectors } from "../features/ChatDB/chatDbMessagesSlice";
4-
import { chatDbSelectors } from "../features/ChatDB/chatDbSlice";
54
import {
6-
sendMessagesThunk,
5+
chatDbMessageSliceActions,
6+
chatDbMessagesSliceSelectors,
7+
} from "../features/ChatDB/chatDbMessagesSlice";
8+
import {
9+
updateCMessagesThunk,
710
updateThreadThunk,
811
} from "../services/refact/chatdb";
912
import { useAppDispatch } from "./useAppDispatch";
1013
import { useSendChatRequest } from "./useSendChatRequest";
11-
import { getSelectedSystemPrompt } from "../features/Chat/Thread/selectors";
14+
import {
15+
getSelectedSystemPrompt,
16+
selectThreadToolUse,
17+
} from "../features/Chat/Thread/selectors";
1218
import { CMessage, SystemMessage } from "../services/refact";
19+
import { useGetCapsQuery } from "./useGetCapsQuery";
20+
import { useGetPromptsQuery } from "./useGetPromptsQuery";
1321

1422
export function useThreadMessageSubmit() {
1523
const dispatch = useAppDispatch();
1624
const { maybeAddImagesToQuestion } = useSendChatRequest();
17-
const systemPrompt = useAppSelector(getSelectedSystemPrompt);
25+
const selectedSystemPrompt = useAppSelector(getSelectedSystemPrompt);
26+
const prompts = useGetPromptsQuery();
27+
const toolUse = useAppSelector(selectThreadToolUse);
28+
const caps = useGetCapsQuery();
1829

1930
const thread = useAppSelector(chatDbMessagesSliceSelectors.selectThread);
2031
const leafPosition = useAppSelector(
2132
chatDbMessagesSliceSelectors.selectLeafEndPosition,
2233
);
2334

24-
const maybeSavedThread = useAppSelector((state) =>
25-
chatDbSelectors.getThreadById(state, thread.cthread_id),
26-
);
35+
const systemMessageText = useMemo(() => {
36+
const defualtPropmpt = prompts.data?.default?.text ?? "";
37+
const selected = Object.values(selectedSystemPrompt);
38+
const prompt = selected.length > 0 ? selected[0].text : defualtPropmpt;
39+
return prompt;
40+
}, [prompts.data, selectedSystemPrompt]);
2741

2842
const isNew = useMemo(() => {
29-
return (
30-
!!maybeSavedThread && leafPosition.num === 0 && leafPosition.alt === 0
31-
);
32-
}, [leafPosition.alt, leafPosition.num, maybeSavedThread]);
43+
return !thread.cthread_id;
44+
}, [thread.cthread_id]);
3345

3446
// TODO: use the hooks from crateApi for submitting threads and messages
3547
const submit = useCallback(
3648
async (question: string) => {
37-
if (isNew) {
38-
const threadThunk = updateThreadThunk(thread);
39-
await dispatch(threadThunk);
40-
}
49+
const threadId = thread.cthread_id || uuidv4();
50+
const threadModel =
51+
(thread.cthread_model || caps.data?.code_chat_default_model) ?? "";
52+
const threadToolUse = (thread.cthread_toolset || toolUse) ?? "";
53+
const newThread = {
54+
...thread,
55+
cthread_id: threadId,
56+
cthread_model: threadModel,
57+
cthread_toolset: threadToolUse,
58+
};
4159

4260
const messagesToSend: CMessage[] = [];
4361

44-
if (
45-
isNew &&
46-
!("default" in systemPrompt) &&
47-
Object.values(systemPrompt).length > 0
48-
) {
62+
console.log({ thread, isNew });
63+
64+
if (isNew) {
65+
const threadThunk = updateThreadThunk(newThread);
66+
await dispatch(threadThunk); // .unwrap(); // TODO: handle errors
67+
// this will subscribe to the thread's message list
68+
dispatch(chatDbMessageSliceActions.setThread(newThread));
69+
4970
const systemMessage: SystemMessage = {
5071
role: "system",
51-
content: Object.values(systemPrompt)[0].text,
72+
content: systemMessageText,
5273
};
5374

5475
const systemCMessage: CMessage = {
55-
cmessage_belongs_to_cthread_id: thread.cthread_id,
76+
cmessage_belongs_to_cthread_id: threadId,
5677
cmessage_alt: 0,
5778
cmessage_num: -1,
5879
cmessage_prev_alt: 0,
59-
cmessage_usage_model: thread.cthread_model,
80+
cmessage_usage_model: threadModel, // could be default
6081
cmessage_usage_prompt: 0,
6182
cmessage_usage_completion: 0,
6283
cmessage_json: systemMessage,
@@ -65,36 +86,36 @@ export function useThreadMessageSubmit() {
6586
messagesToSend.push(systemCMessage);
6687
}
6788

68-
// TODO: add system message
69-
7089
const userMessage = maybeAddImagesToQuestion(question);
7190
const userCMessage: CMessage = {
72-
cmessage_belongs_to_cthread_id: thread.cthread_id,
91+
cmessage_belongs_to_cthread_id: threadId,
7392
cmessage_alt: leafPosition.alt,
74-
cmessage_num: leafPosition.num,
75-
cmessage_prev_alt: leafPosition.alt, // TODO: add this
76-
cmessage_usage_model: thread.cthread_model,
93+
cmessage_num: leafPosition.num + 1,
94+
cmessage_prev_alt: leafPosition.alt, // TODO: add this to end tracker
95+
cmessage_usage_model: threadModel,
7796
cmessage_usage_prompt: 0,
7897
cmessage_usage_completion: 0,
7998
cmessage_json: userMessage,
8099
};
81100

82101
messagesToSend.push(userCMessage);
83102

84-
const thunk = await dispatch(
85-
sendMessagesThunk({ messages: messagesToSend }),
86-
);
103+
console.log({ isNew, messagesToSend });
104+
105+
const thunk = await dispatch(updateCMessagesThunk(messagesToSend));
87106

88107
return thunk;
89108
},
90109
[
110+
caps.data?.code_chat_default_model,
91111
dispatch,
92112
isNew,
93113
leafPosition.alt,
94114
leafPosition.num,
95115
maybeAddImagesToQuestion,
96-
systemPrompt,
116+
systemMessageText,
97117
thread,
118+
toolUse,
98119
],
99120
);
100121

refact-agent/gui/src/hooks/useThreadMessageSubscription.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import { useEffect } from "react";
2-
import { useThreadId } from "./useThreadId";
32
import { useAppDispatch } from "./useAppDispatch";
43
import { subscribeToThreadMessagesThunk } from "../services/refact";
5-
// import { useAppSelector } from "./useAppSelector";
6-
// import { chatDbSelectors } from "../features/ChatDB/chatDbSlice";
4+
import { useAppSelector } from "./useAppSelector";
5+
import { chatDbMessagesSliceSelectors } from "../features/ChatDB/chatDbMessagesSlice";
76

87
export function useThreadMessageSubscription() {
9-
// looks like we need to create the thread before subscribing.
10-
const threadId = useThreadId();
8+
const threadId = useAppSelector(chatDbMessagesSliceSelectors.selectThreadId);
119
const dispatch = useAppDispatch();
1210
useEffect(() => {
11+
console.log("Subscribe to thread messages: " + threadId);
1312
const thunk = dispatch(subscribeToThreadMessagesThunk(threadId));
1413
return () => {
1514
try {
16-
thunk.abort("useThreadMessageSubscription unmounted");
15+
thunk.catch(() => ({}));
16+
thunk.abort(`aborted: subscribeToThreadMessagesThunk(${threadId})`);
1717
} catch (e) {
1818
// no-op
1919
}

refact-agent/gui/src/services/refact/chatdb.ts

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
CHAT_DB_THREADS_SUB,
55
CHAT_DB_MESSAGES_SUB,
66
CHAT_DB_MESSAGES_UPDATE,
7+
CHAT_DB_THREADS_UPDATE,
78
} from "./consts";
89
import { consumeStream } from "../../features/Chat/Thread/utils";
910
import {
@@ -15,10 +16,7 @@ import {
1516
CMessageFromChatDB,
1617
} from "./types";
1718
import { chatDbActions } from "../../features/ChatDB/chatDbSlice";
18-
import {
19-
chatDbMessageSlice,
20-
chatDbMessageSliceActions,
21-
} from "../../features/ChatDB/chatDbMessagesSlice";
19+
import { chatDbMessageSliceActions } from "../../features/ChatDB/chatDbMessagesSlice";
2220

2321
const createAppAsyncThunk = createAsyncThunk.withTypes<{
2422
state: RootState;
@@ -108,7 +106,7 @@ export function updateThread(
108106
port = 8001,
109107
apiKey?: string | null,
110108
): Promise<Response> {
111-
const url = `http://127.0.0.1:${port}${CHAT_DB_THREADS_SUB}`;
109+
const url = `http://127.0.0.1:${port}${CHAT_DB_THREADS_UPDATE}`;
112110
const headers = new Headers();
113111
headers.append("Content-Type", "application/json");
114112
if (apiKey) {
@@ -131,7 +129,11 @@ export const updateThreadThunk = createAppAsyncThunk<
131129
const state = thunkApi.getState() as unknown as RootState;
132130
const port = state.config.lspPort;
133131
const apiKey = state.config.apiKey;
134-
return updateThread(thread, port, apiKey);
132+
console.log("calling updateThread");
133+
return updateThread(thread, port, apiKey).then((res) => {
134+
console.log("update tread done");
135+
return res.json();
136+
});
135137
});
136138

137139
function subscribeToThreadMessages(
@@ -161,6 +163,7 @@ export const subscribeToThreadMessagesThunk = createAppAsyncThunk<
161163
unknown,
162164
string
163165
>("chatDbApi/subscribeToThreadMessages", (cthreadId, thunkApi) => {
166+
if (!cthreadId) return;
164167
const state = thunkApi.getState() as unknown as RootState;
165168
const port = state.config.lspPort;
166169
const apiKey = state.config.apiKey;
@@ -232,27 +235,29 @@ export const updateCMessagesThunk = createAppAsyncThunk<unknown, CMessage[]>(
232235
const state = thunkApi.getState() as unknown as RootState;
233236
const port = state.config.lspPort;
234237
const apiKey = state.config.apiKey;
235-
return updateCMessage(cmessages, port, apiKey);
238+
return updateCMessage(cmessages, port, apiKey).then((res) => res.json());
236239
},
237240
);
238241

239-
export const sendMessagesThunk = createAppAsyncThunk<
240-
unknown,
241-
{
242-
messages: CMessage[];
243-
}
244-
>("chatDbApi/sendThreadAndMessagesThunk", async (args, thunkApi) => {
245-
if (args.messages.length === 0) return;
246-
const id = args.messages.map((m) => m.cmessage_belongs_to_cthread_id)[0];
247-
await thunkApi.dispatch(
248-
updateThreadThunk({
249-
cthread_id: id,
250-
cthread_updated_ts: new Date().getTime(),
251-
}),
252-
);
253-
254-
await thunkApi.dispatch(updateCMessagesThunk(args.messages));
255-
});
242+
// export const sendMessagesThunk = createAppAsyncThunk<
243+
// unknown,
244+
// {
245+
// messages: CMessage[];
246+
// }
247+
// >("chatDbApi/sendThreadAndMessagesThunk", async (args, thunkApi) => {
248+
// if (args.messages.length === 0) return;
249+
// const id = args.messages.map((m) => m.cmessage_belongs_to_cthread_id)[0];
250+
// await thunkApi.dispatch(
251+
// updateThreadThunk({
252+
// cthread_id: id,
253+
// cthread_updated_ts: new Date().getTime(),
254+
// }),
255+
// );
256+
257+
// await thunkApi.dispatch(updateCMessagesThunk(args.messages));
258+
// });
259+
260+
// TODO: create thread an subscribe to messages
256261

257262
// Types for the API
258263

refact-agent/gui/src/services/refact/consts.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ export const KNOWLEDGE_UPDATE_URL = "/v1/mem-upd";
4242
export const KNOWLEDGE_CREATE_URL = "/v1/trajectory-save";
4343
// Chatdblinks
4444
export const CHAT_DB_THREADS_SUB = "/db_v1/cthreads-sub";
45-
export const CHAT_DB_THREADS_UPDATE = "/db_v1/cthreads-update";
45+
export const CHAT_DB_THREADS_UPDATE = "/db_v1/cthread-update";
4646
export const CHAT_DB_MESSAGES_SUB = "/db_v1/cmessages-sub";
4747
export const CHAT_DB_MESSAGES_UPDATE = "/db_v1/cmessages-update";

refact-agent/gui/src/services/refact/types.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -697,13 +697,7 @@ export function isMCPEnvironmentsDict(json: unknown): json is MCPEnvs {
697697

698698
// ChatDB
699699

700-
export type CThreadDefault = {
701-
cthread_id: string;
702-
cthread_title: string;
703-
cthread_toolset: string;
704-
cthread_model: string;
705-
};
706-
export type CThread = CThreadDefault & {
700+
export type CThread = {
707701
cthread_id: string;
708702
cthread_belongs_to_chore_event_id: string | null;
709703
cthread_title: string;
@@ -721,6 +715,13 @@ export type CThread = CThreadDefault & {
721715
cthread_locked_by: string;
722716
cthread_locked_ts: number;
723717
};
718+
719+
// export type CThreadDefault = Partial<CThread> & {
720+
// cthread_id: null | string;
721+
// cthread_title: string;
722+
// cthread_toolset: string;
723+
// cthread_model: string;
724+
// };
724725
export function isCThread(value: unknown): value is CThread {
725726
if (!value || typeof value !== "object") {
726727
return false;

0 commit comments

Comments
 (0)