@langchain/core
Version:
Core LangChain.js abstractions and schemas
266 lines (264 loc) • 8.72 kB
JavaScript
import { __export } from "../_virtual/rolldown_runtime.js";
import { AIMessageChunk } from "../messages/ai.js";
import { applyPatch } from "../utils/fast-json-patch/src/core.js";
import "../utils/fast-json-patch/index.js";
import { BaseTracer } from "./base.js";
import { IterableReadableStream } from "../utils/stream.js";
//#region src/tracers/log_stream.ts
var log_stream_exports = {};
__export(log_stream_exports, {
LogStreamCallbackHandler: () => LogStreamCallbackHandler,
RunLog: () => RunLog,
RunLogPatch: () => RunLogPatch,
isLogStreamHandler: () => isLogStreamHandler
});
/**
* List of jsonpatch JSONPatchOperations, which describe how to create the run state
* from an empty dict. This is the minimal representation of the log, designed to
* be serialized as JSON and sent over the wire to reconstruct the log on the other
* side. Reconstruction of the state can be done with any jsonpatch-compliant library,
* see https://jsonpatch.com for more information.
*/
var RunLogPatch = class {
ops;
constructor(fields) {
this.ops = fields.ops ?? [];
}
concat(other) {
const ops = this.ops.concat(other.ops);
const states = applyPatch({}, ops);
return new RunLog({
ops,
state: states[states.length - 1].newDocument
});
}
};
var RunLog = class RunLog extends RunLogPatch {
state;
constructor(fields) {
super(fields);
this.state = fields.state;
}
concat(other) {
const ops = this.ops.concat(other.ops);
const states = applyPatch(this.state, other.ops);
return new RunLog({
ops,
state: states[states.length - 1].newDocument
});
}
static fromRunLogPatch(patch) {
const states = applyPatch({}, patch.ops);
return new RunLog({
ops: patch.ops,
state: states[states.length - 1].newDocument
});
}
};
const isLogStreamHandler = (handler) => handler.name === "log_stream_tracer";
/**
* Extract standardized inputs from a run.
*
* Standardizes the inputs based on the type of the runnable used.
*
* @param run - Run object
* @param schemaFormat - The schema format to use.
*
* @returns Valid inputs are only dict. By conventions, inputs always represented
* invocation using named arguments.
* A null means that the input is not yet known!
*/
async function _getStandardizedInputs(run, schemaFormat) {
if (schemaFormat === "original") throw new Error("Do not assign inputs with original schema drop the key for now. When inputs are added to streamLog they should be added with standardized schema for streaming events.");
const { inputs } = run;
if ([
"retriever",
"llm",
"prompt"
].includes(run.run_type)) return inputs;
if (Object.keys(inputs).length === 1 && inputs?.input === "") return void 0;
return inputs.input;
}
async function _getStandardizedOutputs(run, schemaFormat) {
const { outputs } = run;
if (schemaFormat === "original") return outputs;
if ([
"retriever",
"llm",
"prompt"
].includes(run.run_type)) return outputs;
if (outputs !== void 0 && Object.keys(outputs).length === 1 && outputs?.output !== void 0) return outputs.output;
return outputs;
}
function isChatGenerationChunk(x) {
return x !== void 0 && x.message !== void 0;
}
/**
* Class that extends the `BaseTracer` class from the
* `langchain.callbacks.tracers.base` module. It represents a callback
* handler that logs the execution of runs and emits `RunLog` instances to a
* `RunLogStream`.
*/
var LogStreamCallbackHandler = class extends BaseTracer {
autoClose = true;
includeNames;
includeTypes;
includeTags;
excludeNames;
excludeTypes;
excludeTags;
_schemaFormat = "original";
rootId;
keyMapByRunId = {};
counterMapByRunName = {};
transformStream;
writer;
receiveStream;
name = "log_stream_tracer";
lc_prefer_streaming = true;
constructor(fields) {
super({
_awaitHandler: true,
...fields
});
this.autoClose = fields?.autoClose ?? true;
this.includeNames = fields?.includeNames;
this.includeTypes = fields?.includeTypes;
this.includeTags = fields?.includeTags;
this.excludeNames = fields?.excludeNames;
this.excludeTypes = fields?.excludeTypes;
this.excludeTags = fields?.excludeTags;
this._schemaFormat = fields?._schemaFormat ?? this._schemaFormat;
this.transformStream = new TransformStream();
this.writer = this.transformStream.writable.getWriter();
this.receiveStream = IterableReadableStream.fromReadableStream(this.transformStream.readable);
}
[Symbol.asyncIterator]() {
return this.receiveStream;
}
async persistRun(_run) {}
_includeRun(run) {
if (run.id === this.rootId) return false;
const runTags = run.tags ?? [];
let include = this.includeNames === void 0 && this.includeTags === void 0 && this.includeTypes === void 0;
if (this.includeNames !== void 0) include = include || this.includeNames.includes(run.name);
if (this.includeTypes !== void 0) include = include || this.includeTypes.includes(run.run_type);
if (this.includeTags !== void 0) include = include || runTags.find((tag) => this.includeTags?.includes(tag)) !== void 0;
if (this.excludeNames !== void 0) include = include && !this.excludeNames.includes(run.name);
if (this.excludeTypes !== void 0) include = include && !this.excludeTypes.includes(run.run_type);
if (this.excludeTags !== void 0) include = include && runTags.every((tag) => !this.excludeTags?.includes(tag));
return include;
}
async *tapOutputIterable(runId, output) {
for await (const chunk of output) {
if (runId !== this.rootId) {
const key = this.keyMapByRunId[runId];
if (key) await this.writer.write(new RunLogPatch({ ops: [{
op: "add",
path: `/logs/${key}/streamed_output/-`,
value: chunk
}] }));
}
yield chunk;
}
}
async onRunCreate(run) {
if (this.rootId === void 0) {
this.rootId = run.id;
await this.writer.write(new RunLogPatch({ ops: [{
op: "replace",
path: "",
value: {
id: run.id,
name: run.name,
type: run.run_type,
streamed_output: [],
final_output: void 0,
logs: {}
}
}] }));
}
if (!this._includeRun(run)) return;
if (this.counterMapByRunName[run.name] === void 0) this.counterMapByRunName[run.name] = 0;
this.counterMapByRunName[run.name] += 1;
const count = this.counterMapByRunName[run.name];
this.keyMapByRunId[run.id] = count === 1 ? run.name : `${run.name}:${count}`;
const logEntry = {
id: run.id,
name: run.name,
type: run.run_type,
tags: run.tags ?? [],
metadata: run.extra?.metadata ?? {},
start_time: new Date(run.start_time).toISOString(),
streamed_output: [],
streamed_output_str: [],
final_output: void 0,
end_time: void 0
};
if (this._schemaFormat === "streaming_events") logEntry.inputs = await _getStandardizedInputs(run, this._schemaFormat);
await this.writer.write(new RunLogPatch({ ops: [{
op: "add",
path: `/logs/${this.keyMapByRunId[run.id]}`,
value: logEntry
}] }));
}
async onRunUpdate(run) {
try {
const runName = this.keyMapByRunId[run.id];
if (runName === void 0) return;
const ops = [];
if (this._schemaFormat === "streaming_events") ops.push({
op: "replace",
path: `/logs/${runName}/inputs`,
value: await _getStandardizedInputs(run, this._schemaFormat)
});
ops.push({
op: "add",
path: `/logs/${runName}/final_output`,
value: await _getStandardizedOutputs(run, this._schemaFormat)
});
if (run.end_time !== void 0) ops.push({
op: "add",
path: `/logs/${runName}/end_time`,
value: new Date(run.end_time).toISOString()
});
const patch = new RunLogPatch({ ops });
await this.writer.write(patch);
} finally {
if (run.id === this.rootId) {
const patch = new RunLogPatch({ ops: [{
op: "replace",
path: "/final_output",
value: await _getStandardizedOutputs(run, this._schemaFormat)
}] });
await this.writer.write(patch);
if (this.autoClose) await this.writer.close();
}
}
}
async onLLMNewToken(run, token, kwargs) {
const runName = this.keyMapByRunId[run.id];
if (runName === void 0) return;
const isChatModel = run.inputs.messages !== void 0;
let streamedOutputValue;
if (isChatModel) if (isChatGenerationChunk(kwargs?.chunk)) streamedOutputValue = kwargs?.chunk;
else streamedOutputValue = new AIMessageChunk({
id: `run-${run.id}`,
content: token
});
else streamedOutputValue = token;
const patch = new RunLogPatch({ ops: [{
op: "add",
path: `/logs/${runName}/streamed_output_str/-`,
value: token
}, {
op: "add",
path: `/logs/${runName}/streamed_output/-`,
value: streamedOutputValue
}] });
await this.writer.write(patch);
}
};
//#endregion
export { LogStreamCallbackHandler, RunLog, RunLogPatch, isLogStreamHandler, log_stream_exports };
//# sourceMappingURL=log_stream.js.map