UNPKG

@langchain/langgraph

Version:
195 lines (194 loc) 7.53 kB
const require_constants = require("../constants.cjs"); const require_config = require("./utils/config.cjs"); const require_io = require("./io.cjs"); const require_subgraph = require("./utils/subgraph.cjs"); let _langchain_langgraph_checkpoint = require("@langchain/langgraph-checkpoint"); //#region src/pregel/debug.ts const COLORS_MAP = { blue: { start: "\x1B[34m", end: "\x1B[0m" }, green: { start: "\x1B[32m", end: "\x1B[0m" }, yellow: { start: "\x1B[33;1m", end: "\x1B[0m" } }; /** * Wrap some text in a color for printing to the console. */ const wrap = (color, text) => `${color.start}${text}${color.end}`; /** * Build the user-meaningful metadata to forward on a task's stream payload. * * Drops langgraph's internal framework keys ({@link EXCLUDED_METADATA_KEYS}) — * which are redundant with the task's own fields and namespace — while keeping * keys like `lc_agent_name`, `ls_integration`, and any user-supplied metadata. * Filtered config tags are folded in under `tags`, mirroring the messages * stream handler. Returns `undefined` when there is nothing to forward. */ function buildTaskMetadata(config) { if (config == null) return void 0; const metadata = {}; if (config.metadata != null) { for (const [key, value] of Object.entries(config.metadata)) if (!_langchain_langgraph_checkpoint.EXCLUDED_METADATA_KEYS.has(key)) metadata[key] = value; } const filteredTags = require_config.filterToUserTags(config.tags); if (filteredTags != null) metadata.tags = filteredTags; return Object.keys(metadata).length > 0 ? metadata : void 0; } function* mapDebugTasks(tasks) { for (const { id, name, input, config, triggers, writes } of tasks) { if (config?.tags?.includes("langsmith:hidden")) continue; const payload = { id, name, input, triggers, interrupts: writes.filter(([writeId, n]) => { return writeId === id && n === "__interrupt__"; }).map(([, v]) => { return v; }) }; const metadata = buildTaskMetadata(config); if (metadata != null) payload.metadata = metadata; yield payload; } } function isMultipleChannelWrite(value) { if (typeof value !== "object" || value === null) return false; return "$writes" in value && Array.isArray(value.$writes); } function mapTaskResultWrites(writes) { const result = {}; for (const [channel, value] of writes) { const strChannel = String(channel); if (strChannel in result) { const channelWrites = isMultipleChannelWrite(result[strChannel]) ? result[strChannel].$writes : [result[strChannel]]; channelWrites.push(value); result[strChannel] = { $writes: channelWrites }; } else result[strChannel] = value; } return result; } function* mapDebugTaskResults(tasks, streamChannels) { for (const [{ id, name, config }, writes] of tasks) { if (config?.tags?.includes("langsmith:hidden")) continue; yield { id, name, result: mapTaskResultWrites(writes.filter(([channel]) => { return Array.isArray(streamChannels) ? streamChannels.includes(channel) : channel === streamChannels; })), interrupts: writes.filter((w) => w[0] === require_constants.INTERRUPT).map((w) => w[1]) }; } } function* mapDebugCheckpoint(config, channels, streamChannels, metadata, tasks, pendingWrites, parentConfig, outputKeys) { function formatConfig(config) { const pyConfig = {}; if (config.callbacks != null) pyConfig.callbacks = config.callbacks; if (config.configurable != null) pyConfig.configurable = config.configurable; if (config.maxConcurrency != null) pyConfig.max_concurrency = config.maxConcurrency; if (config.metadata != null) pyConfig.metadata = config.metadata; if (config.recursionLimit != null) pyConfig.recursion_limit = config.recursionLimit; if (config.runId != null) pyConfig.run_id = config.runId; if (config.runName != null) pyConfig.run_name = config.runName; if (config.tags != null) pyConfig.tags = config.tags; return pyConfig; } const parentNs = config.configurable?.checkpoint_ns; const taskStates = {}; for (const task of tasks) { if (!(task.subgraphs?.length ? task.subgraphs : [task.proc]).find(require_subgraph.findSubgraphPregel)) continue; let taskNs = `${task.name}:${task.id}`; if (parentNs) taskNs = `${parentNs}|${taskNs}`; taskStates[task.id] = { configurable: { thread_id: config.configurable?.thread_id, checkpoint_ns: taskNs } }; } yield { config: formatConfig(config), values: require_io.readChannels(channels, streamChannels), metadata, next: tasks.map((task) => task.name), tasks: tasksWithWrites(tasks, pendingWrites, taskStates, outputKeys), parentConfig: parentConfig ? formatConfig(parentConfig) : void 0 }; } function tasksWithWrites(tasks, pendingWrites, states, outputKeys) { return tasks.map((task) => { const error = pendingWrites.find(([id, n]) => id === task.id && n === "__error__")?.[2]; const interrupts = pendingWrites.filter(([id, n]) => id === task.id && n === "__interrupt__").map(([, , v]) => v); const result = (() => { if (error || interrupts.length || !pendingWrites.length) return void 0; const idx = pendingWrites.findIndex(([tid, n]) => tid === task.id && n === "__return__"); if (idx >= 0) return pendingWrites[idx][2]; if (typeof outputKeys === "string") return pendingWrites.find(([tid, n]) => tid === task.id && n === outputKeys)?.[2]; if (Array.isArray(outputKeys)) { const results = pendingWrites.filter(([tid, n]) => tid === task.id && outputKeys.includes(n)).map(([, n, v]) => [n, v]); if (!results.length) return void 0; return mapTaskResultWrites(results); } })(); if (error) return { id: task.id, name: task.name, path: task.path, error, interrupts, result }; const taskState = states?.[task.id]; return { id: task.id, name: task.name, path: task.path, interrupts, ...taskState !== void 0 ? { state: taskState } : {}, result }; }); } function printStepCheckpoint(step, channels, whitelist) { console.log([ `${wrap(COLORS_MAP.blue, `[${step}:checkpoint]`)}`, `\x1b[1m State at the end of step ${step}:\x1b[0m\n`, JSON.stringify(require_io.readChannels(channels, whitelist), null, 2) ].join("")); } function printStepTasks(step, nextTasks) { const nTasks = nextTasks.length; console.log([ `${wrap(COLORS_MAP.blue, `[${step}:tasks]`)}`, `\x1b[1m Starting step ${step} with ${nTasks} task${nTasks === 1 ? "" : "s"}:\x1b[0m\n`, nextTasks.map((task) => `- ${wrap(COLORS_MAP.green, String(task.name))} -> ${JSON.stringify(task.input, null, 2)}`).join("\n") ].join("")); } function printStepWrites(step, writes, whitelist) { const byChannel = {}; for (const [channel, value] of writes) if (whitelist.includes(channel)) { if (!byChannel[channel]) byChannel[channel] = []; byChannel[channel].push(value); } console.log([ `${wrap(COLORS_MAP.blue, `[${step}:writes]`)}`, `\x1b[1m Finished step ${step} with writes to ${Object.keys(byChannel).length} channel${Object.keys(byChannel).length !== 1 ? "s" : ""}:\x1b[0m\n`, Object.entries(byChannel).map(([name, vals]) => `- ${wrap(COLORS_MAP.yellow, name)} -> ${vals.map((v) => JSON.stringify(v)).join(", ")}`).join("\n") ].join("")); } //#endregion exports.mapDebugCheckpoint = mapDebugCheckpoint; exports.mapDebugTaskResults = mapDebugTaskResults; exports.mapDebugTasks = mapDebugTasks; exports.printStepCheckpoint = printStepCheckpoint; exports.printStepTasks = printStepTasks; exports.printStepWrites = printStepWrites; exports.tasksWithWrites = tasksWithWrites; //# sourceMappingURL=debug.cjs.map