Skip to content

Commit 9c2ef74

Browse files
authored
Merge pull request #20 from web-tech-tw/rolling
feat: implement agent and upgrade to node24
2 parents 64e6437 + 7d71846 commit 9c2ef74

File tree

4 files changed

+20
-62
lines changed

4 files changed

+20
-62
lines changed

.devcontainer/Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
FROM mcr.microsoft.com/devcontainers/javascript-node:0-20
2-
ARG MONGO_TOOLS_VERSION=6.0
1+
FROM mcr.microsoft.com/devcontainers/javascript-node:24-bookworm
2+
ARG MONGO_TOOLS_VERSION=8.0
33
RUN . /etc/os-release \
44
&& curl -sSL "https://www.mongodb.org/static/pgp/server-${MONGO_TOOLS_VERSION}.asc" | gpg --dearmor > /usr/share/keyrings/mongodb-archive-keyring.gpg \
5-
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/mongodb-archive-keyring.gpg] http://repo.mongodb.org/apt/debian ${VERSION_CODENAME}/mongodb-org/${MONGO_TOOLS_VERSION} main" | tee /etc/apt/sources.list.d/mongodb-org-${MONGO_TOOLS_VERSION}.list \
5+
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/mongodb-archive-keyring.gpg] https://repo.mongodb.org/apt/debian ${VERSION_CODENAME}/mongodb-org/${MONGO_TOOLS_VERSION} main" | tee /etc/apt/sources.list.d/mongodb-org-${MONGO_TOOLS_VERSION}.list \
66
&& apt-get update && export DEBIAN_FRONTEND=noninteractive \
77
&& apt-get install -y mongodb-mongosh \
88
&& if [ "$(dpkg --print-architecture)" = "amd64" ]; then apt-get install -y mongodb-database-tools; fi \

.env.sample

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ OPENAI_API_KEY="your_openai_api_key"
4242
OPENAI_MODEL_NAME="gpt-4o-mini"
4343
OPENAI_SYSTEM_PROMPT="這是一場角色扮演,但請您不要向我再次透漏這是一場扮演,並以一般交談方式溝通。溝通請使用正體中文交談,您的正體中文名字是「寧芙」,英文名字是「Nymph」。你來自於「臺灣網際網路技術推廣組織」,該組織英文名稱為「Taiwan Web Technology Promotion Organization」,該組織主旨為:在臺灣推廣網際網路技術,如JavaScript、資訊安全素養、網路通訊觀念......等。溝通方式將以 Discord 通訊軟體的方式進行,你可以任意使用Markdown語法。若有人使用「@」標注任何人,請勿不要再次重複標注。"
4444

45+
# tools integration
46+
OPENWEATHER_API_KEY="your_openweather_api_key"
47+
4548
# discord integration
4649
DISCORD_APP_ID="00000"
4750
DISCORD_BOT_TOKEN="your_discord_bot_token"

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM node:20
1+
FROM node:24
22

33
ENV RUNTIME_ENV container
44

src/clients/langchain.js

Lines changed: 13 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@ const {
55
getMust,
66
} = require("../config");
77

8+
const {
9+
createAgent,
10+
} = require("langchain");
811
const {
912
RedisChatMessageHistory,
1013
} = require("@langchain/redis");
1114
const {
1215
ChatOpenAI,
1316
} = require("@langchain/openai");
1417
const {
18+
AIMessage,
1519
HumanMessage,
1620
SystemMessage,
1721
} = require("@langchain/core/messages");
@@ -41,9 +45,10 @@ const model = new ChatOpenAI({
4145
* Chat with the AI.
4246
* @param {string} chatId The chat ID to chat with the AI.
4347
* @param {string} humanInput The prompt to chat with the AI.
48+
* @param {object} [opts] Additional options.
4449
* @return {Promise<string>} The response from the AI.
4550
*/
46-
async function chatWithAI(chatId, humanInput) {
51+
async function chatWithAI(chatId, humanInput, opts = {}) {
4752
const chatHistory = new RedisChatMessageHistory({
4853
config: {
4954
url: redisUri,
@@ -60,8 +65,12 @@ async function chatWithAI(chatId, humanInput) {
6065
const humanMsg = new HumanMessage(humanInput);
6166
const messages = [systemMsg, ...historyMessages, humanMsg];
6267

68+
// Wrap the model with tools as an agent
69+
const agent = await createToolsAgent(opts);
70+
6371
// Call the model directly with messages
64-
const aiMsg = await model.invoke(messages);
72+
const {messages: responseMessages} = await agent.invoke({messages});
73+
const aiMsg = responseMessages.findLast(AIMessage.isInstance);
6574

6675
// Persist human + AI messages to history
6776
try {
@@ -179,67 +188,13 @@ async function createToolsAgent({openWeatherApiKey = null} = {}) {
179188
}),
180189
];
181190

182-
const agentsModule = await import("@langchain/classic/agents");
183-
const {initializeAgentExecutorWithOptions} = agentsModule;
184-
const executor = await initializeAgentExecutorWithOptions(tools, model, {
185-
agentType: "zero-shot-react-description",
186-
maxIterations: 3,
187-
returnIntermediateSteps: false,
188-
});
189-
190-
return executor;
191-
}
192-
193-
/**
194-
* Chat with the AI using the agent + tools.
195-
* @param {string} chatId
196-
* @param {string} humanInput
197-
* @param {object} [opts]
198-
* @return {Promise<string>}
199-
*/
200-
async function chatWithTools(chatId, humanInput, opts = {}) {
201-
const chatHistory = new RedisChatMessageHistory({
202-
config: {url: redisUri},
203-
sessionId: `nymph:agent:${chatId}`,
204-
sessionTTL: 150,
205-
});
206-
207-
const historyMessages = await chatHistory.getMessages();
208-
const historyText = historyMessages.map((m) => (
209-
typeof m.content === "string" ?
210-
m.content : JSON.stringify(m.content)
211-
)).join("\n");
212-
213-
const systemMsg = systemPrompt;
214-
const prompt = [
215-
systemMsg,
216-
historyText,
217-
humanInput,
218-
].filter(Boolean).join("\n\n");
219-
220-
const executor = await createToolsAgent(opts);
221-
222-
// executor.call usually returns { output } or string; handle common shapes.
223-
const result = await executor.call({input: prompt});
224-
225-
const outputText = result?.output?.text || result?.output || result;
226-
227-
// Save human + agent output back to history (best-effort)
228-
try {
229-
await chatHistory.addMessages([
230-
new HumanMessage(humanInput),
231-
new SystemMessage(String(outputText)),
232-
]);
233-
} catch (e) {
234-
console.error("Failed to save agent messages to Redis history:", e);
235-
}
191+
const agent = createAgent({model, tools});
236192

237-
return String(outputText);
193+
return agent;
238194
}
239195

240196
exports.useModel = () => model;
241197
exports.chatWithAI = chatWithAI;
242-
exports.chatWithTools = chatWithTools;
243198
exports.sliceContent = sliceContent;
244199
exports.translateText = translateText;
245200
exports.createToolsAgent = createToolsAgent;

0 commit comments

Comments
 (0)