UNPKG

@langchain/core

Version:
157 lines (156 loc) 5.51 kB
import { RunTree } from "langsmith/run_trees"; import { getCurrentRunTree } from "langsmith/singletons/traceable"; import { getEnvironmentVariable, getRuntimeEnvironment } from "../utils/env.js"; import { BaseTracer } from "./base.js"; import { getDefaultLangChainClientSingleton } from "../singletons/tracer.js"; export class LangChainTracer extends BaseTracer { constructor(fields = {}) { super(fields); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: "langchain_tracer" }); Object.defineProperty(this, "projectName", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "exampleId", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "client", { enumerable: true, configurable: true, writable: true, value: void 0 }); const { exampleId, projectName, client } = fields; this.projectName = projectName ?? getEnvironmentVariable("LANGCHAIN_PROJECT") ?? getEnvironmentVariable("LANGCHAIN_SESSION"); this.exampleId = exampleId; this.client = client ?? getDefaultLangChainClientSingleton(); const traceableTree = LangChainTracer.getTraceableRunTree(); if (traceableTree) { this.updateFromRunTree(traceableTree); } } async _convertToCreate(run, example_id = undefined) { return { ...run, extra: { ...run.extra, runtime: await getRuntimeEnvironment(), }, child_runs: undefined, session_name: this.projectName, reference_example_id: run.parent_run_id ? undefined : example_id, }; } async persistRun(_run) { } async onRunCreate(run) { const persistedRun = await this._convertToCreate(run, this.exampleId); await this.client.createRun(persistedRun); } async onRunUpdate(run) { const runUpdate = { end_time: run.end_time, error: run.error, outputs: run.outputs, events: run.events, inputs: run.inputs, trace_id: run.trace_id, dotted_order: run.dotted_order, parent_run_id: run.parent_run_id, extra: run.extra, }; await this.client.updateRun(run.id, runUpdate); } getRun(id) { return this.runMap.get(id); } updateFromRunTree(runTree) { let rootRun = runTree; const visited = new Set(); while (rootRun.parent_run) { if (visited.has(rootRun.id)) break; visited.add(rootRun.id); if (!rootRun.parent_run) break; rootRun = rootRun.parent_run; } visited.clear(); const queue = [rootRun]; while (queue.length > 0) { const current = queue.shift(); if (!current || visited.has(current.id)) continue; visited.add(current.id); // @ts-expect-error Types of property 'events' are incompatible. this.runMap.set(current.id, current); if (current.child_runs) { queue.push(...current.child_runs); } } this.client = runTree.client ?? this.client; this.projectName = runTree.project_name ?? this.projectName; this.exampleId = runTree.reference_example_id ?? this.exampleId; } convertToRunTree(id) { const runTreeMap = {}; const runTreeList = []; for (const [id, run] of this.runMap) { // by converting the run map to a run tree, we are doing a copy // thus, any mutation performed on the run tree will not be reflected // back in the run map // TODO: Stop using `this.runMap` in favour of LangSmith's `RunTree` const runTree = new RunTree({ ...run, child_runs: [], parent_run: undefined, // inherited properties client: this.client, project_name: this.projectName, reference_example_id: this.exampleId, tracingEnabled: true, }); runTreeMap[id] = runTree; runTreeList.push([id, run.dotted_order]); } runTreeList.sort((a, b) => { if (!a[1] || !b[1]) return 0; return a[1].localeCompare(b[1]); }); for (const [id] of runTreeList) { const run = this.runMap.get(id); const runTree = runTreeMap[id]; if (!run || !runTree) continue; if (run.parent_run_id) { const parentRunTree = runTreeMap[run.parent_run_id]; if (parentRunTree) { parentRunTree.child_runs.push(runTree); runTree.parent_run = parentRunTree; } } } return runTreeMap[id]; } static getTraceableRunTree() { try { return getCurrentRunTree(); } catch { return undefined; } } }