const BASE_URL = process.env.LANGGRAPH_URL || "http://192.168.0.100:2026"; const ASSISTANT_ID = process.env.ASSISTANT_ID || "student_score"; const QUESTION = process.env.QUESTION || "白若耶最近10次数学考试的成绩趋势怎么样"; const CONTEXT = { team_id: process.env.TEAM_ID || "19", env: process.env.AGENT_ENV || "dev", }; function parseJson(text) { try { return JSON.parse(text); } catch { return text; } } async function createThread() { const response = await fetch(`${BASE_URL}/threads`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({}), }); if (!response.ok) { throw new Error(`create thread failed: ${response.status} ${await response.text()}`); } const thread = await response.json(); return thread.thread_id; } function pickFinalAnswer(data) { if (!data || typeof data !== "object" || Array.isArray(data)) { return ""; } const renderAnswer = data.render_answer; if (renderAnswer && typeof renderAnswer.answer === "string") { return renderAnswer.answer; } if (typeof data.answer === "string") { return data.answer; } return ""; } function pickReasoning(data) { if (!data || typeof data !== "object" || Array.isArray(data)) { return ""; } const renderAnswer = data.render_answer; if (renderAnswer && typeof renderAnswer.reasoning === "string") { return renderAnswer.reasoning; } if (typeof data.reasoning === "string") { return data.reasoning; } return ""; } function handleEvent(eventName, dataText, answerParts, finalAnswers) { const data = parseJson(dataText); if (eventName === "updates") { const finalAnswer = pickFinalAnswer(data); const reasoning = pickReasoning(data); if (data && typeof data === "object" && !Array.isArray(data)) { console.log(`\n[updates] ${Object.keys(data).join(", ")}`); } else { console.log("\n[updates]", data); } if (reasoning) { console.log("\n[reasoning]"); console.log(reasoning); } if (finalAnswer) { finalAnswers.push(finalAnswer); console.log("\n[final.answer]"); console.log(finalAnswer); } return; } if (eventName === "messages") { const messageChunk = Array.isArray(data) ? data[0] : undefined; const content = messageChunk && typeof messageChunk.content === "string" ? messageChunk.content : ""; if (content) { answerParts.push(content); process.stdout.write(content); } return; } if (eventName) { console.log(`\n[${eventName}]`, data); } } async function readSse(response) { if (!response.body) { throw new Error("response body is empty"); } const reader = response.body.getReader(); const decoder = new TextDecoder("utf-8"); const answerParts = []; const finalAnswers = []; let buffer = ""; while (true) { const { value, done } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const events = buffer.split(/\r?\n\r?\n/); buffer = events.pop() || ""; for (const rawEvent of events) { let eventName = ""; const dataLines = []; for (const line of rawEvent.split(/\r?\n/)) { if (line.startsWith("event:")) { eventName = line.slice("event:".length).trim(); } else if (line.startsWith("data:")) { dataLines.push(line.slice("data:".length).trimStart()); } } handleEvent(eventName, dataLines.join("\n"), answerParts, finalAnswers); } } if (buffer.trim()) { handleEvent("", buffer.trim(), answerParts, finalAnswers); } return finalAnswers.at(-1) || answerParts.join(""); } async function main() { const threadId = await createThread(); const endpoint = `${BASE_URL}/threads/${threadId}/runs/stream`; const started = Date.now(); console.log("=== LangGraph fetch stream test ==="); console.log(`base_url: ${BASE_URL}`); console.log(`assistant_id: ${ASSISTANT_ID}`); console.log(`thread_id: ${threadId}`); console.log(""); const response = await fetch(endpoint, { method: "POST", headers: { "Content-Type": "application/json", Accept: "text/event-stream", }, body: JSON.stringify({ assistant_id: ASSISTANT_ID, input: { question: QUESTION }, context: CONTEXT, stream_mode: ["updates", "messages-tuple"], }), }); if (!response.ok) { throw new Error(`stream request failed: ${response.status} ${await response.text()}`); } const answer = await readSse(response); const elapsed = ((Date.now() - started) / 1000).toFixed(2); console.log(`\n\n=== done: ${elapsed}s, answer length: ${answer.length} ===`); } main().catch((error) => { console.error(error); process.exitCode = 1; });