@langchain/langgraph
Version:
LangGraph
175 lines (173 loc) • 6.49 kB
JavaScript
const require_constants = require('../constants.cjs');
const require_io = require('./io.cjs');
const require_subgraph = require('./utils/subgraph.cjs');
//#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}`;
function* mapDebugTasks(tasks) {
for (const { id, name, input, config, triggers, writes } of tasks) {
if (config?.tags?.includes(require_constants.TAG_HIDDEN)) continue;
const interrupts = writes.filter(([writeId, n]) => {
return writeId === id && n === require_constants.INTERRUPT;
}).map(([, v]) => {
return v;
});
yield {
id,
name,
input,
triggers,
interrupts
};
}
}
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(require_constants.TAG_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$1) {
const pyConfig = {};
if (config$1.callbacks != null) pyConfig.callbacks = config$1.callbacks;
if (config$1.configurable != null) pyConfig.configurable = config$1.configurable;
if (config$1.maxConcurrency != null) pyConfig.max_concurrency = config$1.maxConcurrency;
if (config$1.metadata != null) pyConfig.metadata = config$1.metadata;
if (config$1.recursionLimit != null) pyConfig.recursion_limit = config$1.recursionLimit;
if (config$1.runId != null) pyConfig.run_id = config$1.runId;
if (config$1.runName != null) pyConfig.run_name = config$1.runName;
if (config$1.tags != null) pyConfig.tags = config$1.tags;
return pyConfig;
}
const parentNs = config.configurable?.checkpoint_ns;
const taskStates = {};
for (const task of tasks) {
const candidates = task.subgraphs?.length ? task.subgraphs : [task.proc];
if (!candidates.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 === require_constants.ERROR)?.[2];
const interrupts = pendingWrites.filter(([id, n]) => id === task.id && n === require_constants.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 === require_constants.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);
}
return void 0;
})();
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