-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathanswerUser.ts
123 lines (115 loc) · 3.55 KB
/
answerUser.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import { handleModeration } from "./handleModeration";
import { runChain } from "../chains/summaryBufferMemoryWithFunctions";
import { createServiceClient } from "../createServiceClient";
import { CallbackHandler } from "langfuse-langchain";
import {
LANGFUSE_BASE_URL,
LANGFUSE_PUBLIC_KEY,
LANGFUSE_SECRET_KEY,
} from "../config";
import { Logger } from "pino";
import { loadTools } from "../../examples/nitro/tools/nitroTools";
import { Callbacks } from "langchain/callbacks";
import { AgentExecutor } from "langchain/agents";
import { ChatsRow, DatabaseTable } from "../types";
export async function answerUser(chat: ChatsRow, logger: Logger) {
const serviceClient = createServiceClient();
const { data: chatMessages, error } = await serviceClient
.from("chat_messages")
.select("*")
.eq("chat_id", chat.id)
.order("created_at", { ascending: true });
try {
if (error) {
throw new Error(error.message);
}
if (!chatMessages) {
throw new Error("No chat found");
}
if (chatMessages.length < 2) {
throw new Error("Not enough chat messages");
}
} catch (error) {
logger.error({
op: "answerUser validation",
error: error instanceof Error ? error.message : error,
});
throw error instanceof Error
? error
: new Error("Cannot retrieve messages");
}
const lastUserMessage = chatMessages.at(-2);
const lastAssistantMessage = chatMessages.at(-1);
try {
if (!lastUserMessage || lastUserMessage.role !== "user") {
throw new Error("No last user message found");
}
if (!lastAssistantMessage || lastAssistantMessage.role !== "assistant") {
throw new Error("No last assistant message found");
}
} catch (error) {
logger.error({
op: "answerUser validation",
error: error instanceof Error ? error.message : error,
});
throw error instanceof Error
? error
: new Error("Cannot retrieve last user message");
}
function saveAnswer(answer: string) {
return serviceClient
.from("chat_messages")
.update({
content: answer,
finished: true,
})
.eq("id", lastAssistantMessage!.id)
.select()
.single()
.then(({ data, error }) => {
logger.info({ op: "answerUser saveAnswer", data, error });
if (error) {
throw new Error(error.message);
}
if (!data) {
throw new Error("Empty data");
}
return data as DatabaseTable<"chat_messages", "Row"> & {
role: "assistant";
finished: true;
};
});
}
try {
// TODO: should the moderation and intent determination be done in parallel?
await handleModeration({
chatMessages,
});
const agentCallbackHandler = new CallbackHandler({
publicKey: LANGFUSE_PUBLIC_KEY,
secretKey: LANGFUSE_SECRET_KEY,
baseUrl: LANGFUSE_BASE_URL,
userId: chat.id,
});
const callbacks: Callbacks = [agentCallbackHandler];
const nitroTools = await loadTools({
callbacks,
});
const tools: AgentExecutor["tools"] = [...Object.values(nitroTools)];
const assistantAnswer = await runChain({
chatMessages,
systemPrompt: chat.metadata!.systemPrompt as string,
callbacks,
tools,
runnerOptions: {},
});
await agentCallbackHandler.shutdownAsync();
return saveAnswer(assistantAnswer);
} catch (error) {
logger.error({
op: "answerUser processing",
error: error instanceof Error ? error.message : error,
});
return saveAnswer(`Sorry, something went wrong`);
}
}