"use client"; import { Client as LangGraphClient } from "@langchain/langgraph-sdk/client"; import { getLangGraphBaseURL } from "../config"; import { isStaticWebsiteOnly } from "../static-mode"; import { loadStaticDemoThread, loadStaticDemoThreads, staticDemoThreadState, } from "../threads/static-demo"; import type { AgentThreadState } from "../threads/types"; import { isStateChangingMethod, readCsrfCookie } from "./fetcher"; import { sanitizeRunStreamOptions } from "./stream-mode"; /** * SDK ``onRequest`` hook that mints the ``X-CSRF-Token`` header from the * live ``csrf_token`` cookie just before each outbound fetch. * * Reading the cookie per-request (rather than baking it into the SDK's * ``defaultHeaders`` at construction) handles login / logout / password * change cookie rotation transparently. Both the ``/api/langgraph/*`` SDK * path and the direct REST endpoints in ``fetcher.ts:fetchWithAuth`` * share :func:`readCsrfCookie` and :const:`STATE_CHANGING_METHODS` so * the contract stays in lockstep. */ function injectCsrfHeader(_url: URL, init: RequestInit): RequestInit { if (!isStateChangingMethod(init.method ?? "GET")) { return init; } const token = readCsrfCookie(); if (!token) return init; const headers = new Headers(init.headers); if (!headers.has("X-CSRF-Token")) { headers.set("X-CSRF-Token", token); } return { ...init, headers }; } function createCompatibleClient(isMock?: boolean): LangGraphClient { if (isStaticWebsiteOnly() && !isMock) { return createStaticClient(); } const apiUrl = getLangGraphBaseURL(isMock); console.log(`Creating API client with base URL: ${apiUrl}`); const client = new LangGraphClient({ apiUrl, onRequest: injectCsrfHeader, }); const originalRunStream = client.runs.stream.bind(client.runs); client.runs.stream = ((threadId, assistantId, payload) => originalRunStream( threadId, assistantId, sanitizeRunStreamOptions(payload), )) as typeof client.runs.stream; const originalJoinStream = client.runs.joinStream.bind(client.runs); client.runs.joinStream = ((threadId, runId, options) => originalJoinStream( threadId, runId, sanitizeRunStreamOptions(options), )) as typeof client.runs.joinStream; return client; } function createStaticClient(): LangGraphClient { const apiUrl = typeof window === "undefined" ? "http://localhost:3000" : window.location.origin; const client = new LangGraphClient({ apiUrl }); client.threads.search = (async (query) => { return loadStaticDemoThreads(query); }) as typeof client.threads.search; client.threads.get = (async (threadId) => { return loadStaticDemoThread(threadId); }) as typeof client.threads.get; client.threads.getState = (async (threadId) => { return staticDemoThreadState(await loadStaticDemoThread(threadId)); }) as typeof client.threads.getState; client.threads.getHistory = (async (threadId) => { return [staticDemoThreadState(await loadStaticDemoThread(threadId))]; }) as typeof client.threads.getHistory; client.threads.update = (async (threadId) => { return loadStaticDemoThread(threadId); }) as typeof client.threads.update; client.runs.list = (async () => []) as typeof client.runs.list; client.runs.stream = async function* () { /* empty */ } as typeof client.runs.stream; client.runs.joinStream = async function* () { /* empty */ } as typeof client.runs.joinStream; return client as LangGraphClient; } const _clients = new Map(); export function getAPIClient(isMock?: boolean): LangGraphClient { const cacheKey = isMock ? "mock" : "default"; let client = _clients.get(cacheKey); if (!client) { client = createCompatibleClient(isMock); _clients.set(cacheKey, client); } return client; }