@langchain/langgraph
Version:
LangGraph
230 lines • 8.15 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.wrap = void 0;
exports.printCheckpoint = printCheckpoint;
exports._readChannels = _readChannels;
exports.mapDebugTasks = mapDebugTasks;
exports.mapDebugTaskResults = mapDebugTaskResults;
exports.mapDebugCheckpoint = mapDebugCheckpoint;
exports.tasksWithWrites = tasksWithWrites;
exports.printStepCheckpoint = printStepCheckpoint;
exports.printStepTasks = printStepTasks;
exports.printStepWrites = printStepWrites;
const constants_js_1 = require("../constants.cjs");
const errors_js_1 = require("../errors.cjs");
const io_js_1 = require("./io.cjs");
const subgraph_js_1 = require("./utils/subgraph.cjs");
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}`;
exports.wrap = wrap;
function printCheckpoint(step, channels) {
console.log([
`${(0, exports.wrap)(COLORS_MAP.blue, "[langgraph/checkpoint]")}`,
`Finishing step ${step}. Channel values:\n`,
`\n${JSON.stringify(Object.fromEntries(_readChannels(channels)), null, 2)}`,
].join(""));
}
function* _readChannels(channels
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) {
for (const [name, channel] of Object.entries(channels)) {
try {
yield [name, channel.get()];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}
catch (error) {
if (error.name === errors_js_1.EmptyChannelError.unminifiable_name) {
// Skip the channel if it's empty
continue;
}
else {
throw error; // Re-throw the error if it's not an EmptyChannelError
}
}
}
}
function* mapDebugTasks(step, tasks) {
const ts = new Date().toISOString();
for (const { id, name, input, config, triggers, writes } of tasks) {
if (config?.tags?.includes(constants_js_1.TAG_HIDDEN))
continue;
const interrupts = writes
.filter(([writeId, n]) => {
return writeId === id && n === constants_js_1.INTERRUPT;
})
.map(([, v]) => {
return v;
});
yield {
type: "task",
timestamp: ts,
step,
payload: {
id,
name,
input,
triggers,
interrupts,
},
};
}
}
function* mapDebugTaskResults(step, tasks, streamChannels) {
const ts = new Date().toISOString();
for (const [{ id, name, config }, writes] of tasks) {
if (config?.tags?.includes(constants_js_1.TAG_HIDDEN))
continue;
yield {
type: "task_result",
timestamp: ts,
step,
payload: {
id,
name,
result: writes.filter(([channel]) => {
return Array.isArray(streamChannels)
? streamChannels.includes(channel)
: channel === streamChannels;
}),
interrupts: writes.filter((w) => w[0] === constants_js_1.INTERRUPT).map((w) => w[1]),
},
};
}
}
function* mapDebugCheckpoint(step, config, channels, streamChannels, metadata, tasks, pendingWrites, parentConfig) {
function formatConfig(config) {
// make sure the config is consistent with Python
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) {
const candidates = task.subgraphs?.length ? task.subgraphs : [task.proc];
if (!candidates.find(subgraph_js_1.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,
},
};
}
const ts = new Date().toISOString();
yield {
type: "checkpoint",
timestamp: ts,
step,
payload: {
config: formatConfig(config),
values: (0, io_js_1.readChannels)(channels, streamChannels),
metadata,
next: tasks.map((task) => task.name),
tasks: tasksWithWrites(tasks, pendingWrites, taskStates),
parentConfig: parentConfig ? formatConfig(parentConfig) : undefined,
},
};
}
function tasksWithWrites(tasks, pendingWrites, states) {
return tasks.map((task) => {
const error = pendingWrites.find(([id, n]) => id === task.id && n === constants_js_1.ERROR)?.[2];
const interrupts = pendingWrites
.filter(([id, n]) => {
return id === task.id && n === constants_js_1.INTERRUPT;
})
.map(([, , v]) => {
return v;
});
if (error) {
return {
id: task.id,
name: task.name,
path: task.path,
error,
interrupts,
};
}
const taskState = states?.[task.id];
return {
id: task.id,
name: task.name,
path: task.path,
interrupts,
...(taskState !== undefined ? { state: taskState } : {}),
};
});
}
function printStepCheckpoint(step, channels, whitelist) {
console.log([
`${(0, exports.wrap)(COLORS_MAP.blue, `[${step}:checkpoint]`)}`,
`\x1b[1m State at the end of step ${step}:\x1b[0m\n`,
JSON.stringify((0, io_js_1.readChannels)(channels, whitelist), null, 2),
].join(""));
}
function printStepTasks(step, nextTasks) {
const nTasks = nextTasks.length;
console.log([
`${(0, exports.wrap)(COLORS_MAP.blue, `[${step}:tasks]`)}`,
`\x1b[1m Starting step ${step} with ${nTasks} task${nTasks === 1 ? "" : "s"}:\x1b[0m\n`,
nextTasks
.map((task) => `- ${(0, exports.wrap)(COLORS_MAP.green, String(task.name))} -> ${JSON.stringify(task.input, null, 2)}`)
.join("\n"),
].join(""));
}
function printStepWrites(step, writes, whitelist) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const byChannel = {};
for (const [channel, value] of writes) {
if (whitelist.includes(channel)) {
if (!byChannel[channel]) {
byChannel[channel] = [];
}
byChannel[channel].push(value);
}
}
console.log([
`${(0, exports.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]) => `- ${(0, exports.wrap)(COLORS_MAP.yellow, name)} -> ${vals
.map((v) => JSON.stringify(v))
.join(", ")}`)
.join("\n"),
].join(""));
}
//# sourceMappingURL=debug.js.map
;