run_trees.cjs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. "use strict";
  2. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  3. if (k2 === undefined) k2 = k;
  4. var desc = Object.getOwnPropertyDescriptor(m, k);
  5. if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
  6. desc = { enumerable: true, get: function() { return m[k]; } };
  7. }
  8. Object.defineProperty(o, k2, desc);
  9. }) : (function(o, m, k, k2) {
  10. if (k2 === undefined) k2 = k;
  11. o[k2] = m[k];
  12. }));
  13. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  14. Object.defineProperty(o, "default", { enumerable: true, value: v });
  15. }) : function(o, v) {
  16. o["default"] = v;
  17. });
  18. var __importStar = (this && this.__importStar) || (function () {
  19. var ownKeys = function(o) {
  20. ownKeys = Object.getOwnPropertyNames || function (o) {
  21. var ar = [];
  22. for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
  23. return ar;
  24. };
  25. return ownKeys(o);
  26. };
  27. return function (mod) {
  28. if (mod && mod.__esModule) return mod;
  29. var result = {};
  30. if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
  31. __setModuleDefault(result, mod);
  32. return result;
  33. };
  34. })();
  35. Object.defineProperty(exports, "__esModule", { value: true });
  36. exports.RunTree = void 0;
  37. exports.convertToDottedOrderFormat = convertToDottedOrderFormat;
  38. exports.isRunTree = isRunTree;
  39. exports.isRunnableConfigLike = isRunnableConfigLike;
  40. const uuid = __importStar(require("uuid"));
  41. const env_js_1 = require("./utils/env.cjs");
  42. const client_js_1 = require("./client.cjs");
  43. const env_js_2 = require("./env.cjs");
  44. const warn_js_1 = require("./utils/warn.cjs");
  45. const constants_js_1 = require("./singletons/constants.cjs");
  46. function stripNonAlphanumeric(input) {
  47. return input.replace(/[-:.]/g, "");
  48. }
  49. function convertToDottedOrderFormat(epoch, runId, executionOrder = 1) {
  50. // Date only has millisecond precision, so we use the microseconds to break
  51. // possible ties, avoiding incorrect run order
  52. const paddedOrder = executionOrder.toFixed(0).slice(0, 3).padStart(3, "0");
  53. return (stripNonAlphanumeric(`${new Date(epoch).toISOString().slice(0, -1)}${paddedOrder}Z`) + runId);
  54. }
  55. /**
  56. * Baggage header information
  57. */
  58. class Baggage {
  59. constructor(metadata, tags, project_name) {
  60. Object.defineProperty(this, "metadata", {
  61. enumerable: true,
  62. configurable: true,
  63. writable: true,
  64. value: void 0
  65. });
  66. Object.defineProperty(this, "tags", {
  67. enumerable: true,
  68. configurable: true,
  69. writable: true,
  70. value: void 0
  71. });
  72. Object.defineProperty(this, "project_name", {
  73. enumerable: true,
  74. configurable: true,
  75. writable: true,
  76. value: void 0
  77. });
  78. this.metadata = metadata;
  79. this.tags = tags;
  80. this.project_name = project_name;
  81. }
  82. static fromHeader(value) {
  83. const items = value.split(",");
  84. let metadata = {};
  85. let tags = [];
  86. let project_name;
  87. for (const item of items) {
  88. const [key, uriValue] = item.split("=");
  89. const value = decodeURIComponent(uriValue);
  90. if (key === "langsmith-metadata") {
  91. metadata = JSON.parse(value);
  92. }
  93. else if (key === "langsmith-tags") {
  94. tags = value.split(",");
  95. }
  96. else if (key === "langsmith-project") {
  97. project_name = value;
  98. }
  99. }
  100. return new Baggage(metadata, tags, project_name);
  101. }
  102. toHeader() {
  103. const items = [];
  104. if (this.metadata && Object.keys(this.metadata).length > 0) {
  105. items.push(`langsmith-metadata=${encodeURIComponent(JSON.stringify(this.metadata))}`);
  106. }
  107. if (this.tags && this.tags.length > 0) {
  108. items.push(`langsmith-tags=${encodeURIComponent(this.tags.join(","))}`);
  109. }
  110. if (this.project_name) {
  111. items.push(`langsmith-project=${encodeURIComponent(this.project_name)}`);
  112. }
  113. return items.join(",");
  114. }
  115. }
  116. class RunTree {
  117. constructor(originalConfig) {
  118. Object.defineProperty(this, "id", {
  119. enumerable: true,
  120. configurable: true,
  121. writable: true,
  122. value: void 0
  123. });
  124. Object.defineProperty(this, "name", {
  125. enumerable: true,
  126. configurable: true,
  127. writable: true,
  128. value: void 0
  129. });
  130. Object.defineProperty(this, "run_type", {
  131. enumerable: true,
  132. configurable: true,
  133. writable: true,
  134. value: void 0
  135. });
  136. Object.defineProperty(this, "project_name", {
  137. enumerable: true,
  138. configurable: true,
  139. writable: true,
  140. value: void 0
  141. });
  142. Object.defineProperty(this, "parent_run", {
  143. enumerable: true,
  144. configurable: true,
  145. writable: true,
  146. value: void 0
  147. });
  148. Object.defineProperty(this, "child_runs", {
  149. enumerable: true,
  150. configurable: true,
  151. writable: true,
  152. value: void 0
  153. });
  154. Object.defineProperty(this, "start_time", {
  155. enumerable: true,
  156. configurable: true,
  157. writable: true,
  158. value: void 0
  159. });
  160. Object.defineProperty(this, "end_time", {
  161. enumerable: true,
  162. configurable: true,
  163. writable: true,
  164. value: void 0
  165. });
  166. Object.defineProperty(this, "extra", {
  167. enumerable: true,
  168. configurable: true,
  169. writable: true,
  170. value: void 0
  171. });
  172. Object.defineProperty(this, "tags", {
  173. enumerable: true,
  174. configurable: true,
  175. writable: true,
  176. value: void 0
  177. });
  178. Object.defineProperty(this, "error", {
  179. enumerable: true,
  180. configurable: true,
  181. writable: true,
  182. value: void 0
  183. });
  184. Object.defineProperty(this, "serialized", {
  185. enumerable: true,
  186. configurable: true,
  187. writable: true,
  188. value: void 0
  189. });
  190. Object.defineProperty(this, "inputs", {
  191. enumerable: true,
  192. configurable: true,
  193. writable: true,
  194. value: void 0
  195. });
  196. Object.defineProperty(this, "outputs", {
  197. enumerable: true,
  198. configurable: true,
  199. writable: true,
  200. value: void 0
  201. });
  202. Object.defineProperty(this, "reference_example_id", {
  203. enumerable: true,
  204. configurable: true,
  205. writable: true,
  206. value: void 0
  207. });
  208. Object.defineProperty(this, "client", {
  209. enumerable: true,
  210. configurable: true,
  211. writable: true,
  212. value: void 0
  213. });
  214. Object.defineProperty(this, "events", {
  215. enumerable: true,
  216. configurable: true,
  217. writable: true,
  218. value: void 0
  219. });
  220. Object.defineProperty(this, "trace_id", {
  221. enumerable: true,
  222. configurable: true,
  223. writable: true,
  224. value: void 0
  225. });
  226. Object.defineProperty(this, "dotted_order", {
  227. enumerable: true,
  228. configurable: true,
  229. writable: true,
  230. value: void 0
  231. });
  232. Object.defineProperty(this, "tracingEnabled", {
  233. enumerable: true,
  234. configurable: true,
  235. writable: true,
  236. value: void 0
  237. });
  238. Object.defineProperty(this, "execution_order", {
  239. enumerable: true,
  240. configurable: true,
  241. writable: true,
  242. value: void 0
  243. });
  244. Object.defineProperty(this, "child_execution_order", {
  245. enumerable: true,
  246. configurable: true,
  247. writable: true,
  248. value: void 0
  249. });
  250. /**
  251. * Attachments associated with the run.
  252. * Each entry is a tuple of [mime_type, bytes]
  253. */
  254. Object.defineProperty(this, "attachments", {
  255. enumerable: true,
  256. configurable: true,
  257. writable: true,
  258. value: void 0
  259. });
  260. // If you pass in a run tree directly, return a shallow clone
  261. if (isRunTree(originalConfig)) {
  262. Object.assign(this, { ...originalConfig });
  263. return;
  264. }
  265. const defaultConfig = RunTree.getDefaultConfig();
  266. const { metadata, ...config } = originalConfig;
  267. const client = config.client ?? RunTree.getSharedClient();
  268. const dedupedMetadata = {
  269. ...metadata,
  270. ...config?.extra?.metadata,
  271. };
  272. config.extra = { ...config.extra, metadata: dedupedMetadata };
  273. Object.assign(this, { ...defaultConfig, ...config, client });
  274. if (!this.trace_id) {
  275. if (this.parent_run) {
  276. this.trace_id = this.parent_run.trace_id ?? this.id;
  277. }
  278. else {
  279. this.trace_id = this.id;
  280. }
  281. }
  282. this.execution_order ??= 1;
  283. this.child_execution_order ??= 1;
  284. if (!this.dotted_order) {
  285. const currentDottedOrder = convertToDottedOrderFormat(this.start_time, this.id, this.execution_order);
  286. if (this.parent_run) {
  287. this.dotted_order =
  288. this.parent_run.dotted_order + "." + currentDottedOrder;
  289. }
  290. else {
  291. this.dotted_order = currentDottedOrder;
  292. }
  293. }
  294. }
  295. static getDefaultConfig() {
  296. return {
  297. id: uuid.v4(),
  298. run_type: "chain",
  299. project_name: (0, env_js_1.getLangSmithEnvironmentVariable)("PROJECT") ??
  300. (0, env_js_1.getEnvironmentVariable)("LANGCHAIN_SESSION") ?? // TODO: Deprecate
  301. "default",
  302. child_runs: [],
  303. api_url: (0, env_js_1.getEnvironmentVariable)("LANGCHAIN_ENDPOINT") ?? "http://localhost:1984",
  304. api_key: (0, env_js_1.getEnvironmentVariable)("LANGCHAIN_API_KEY"),
  305. caller_options: {},
  306. start_time: Date.now(),
  307. serialized: {},
  308. inputs: {},
  309. extra: {},
  310. };
  311. }
  312. static getSharedClient() {
  313. if (!RunTree.sharedClient) {
  314. RunTree.sharedClient = new client_js_1.Client();
  315. }
  316. return RunTree.sharedClient;
  317. }
  318. createChild(config) {
  319. const child_execution_order = this.child_execution_order + 1;
  320. const child = new RunTree({
  321. ...config,
  322. parent_run: this,
  323. project_name: this.project_name,
  324. client: this.client,
  325. tracingEnabled: this.tracingEnabled,
  326. execution_order: child_execution_order,
  327. child_execution_order: child_execution_order,
  328. });
  329. // Copy context vars over into the new run tree.
  330. if (constants_js_1._LC_CONTEXT_VARIABLES_KEY in this) {
  331. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  332. child[constants_js_1._LC_CONTEXT_VARIABLES_KEY] =
  333. this[constants_js_1._LC_CONTEXT_VARIABLES_KEY];
  334. }
  335. const LC_CHILD = Symbol.for("lc:child_config");
  336. const presentConfig = config.extra?.[LC_CHILD] ??
  337. this.extra[LC_CHILD];
  338. // tracing for LangChain is defined by the _parentRunId and runMap of the tracer
  339. if (isRunnableConfigLike(presentConfig)) {
  340. const newConfig = { ...presentConfig };
  341. const callbacks = isCallbackManagerLike(newConfig.callbacks)
  342. ? newConfig.callbacks.copy?.()
  343. : undefined;
  344. if (callbacks) {
  345. // update the parent run id
  346. Object.assign(callbacks, { _parentRunId: child.id });
  347. // only populate if we're in a newer LC.JS version
  348. callbacks.handlers
  349. ?.find(isLangChainTracerLike)
  350. ?.updateFromRunTree?.(child);
  351. newConfig.callbacks = callbacks;
  352. }
  353. child.extra[LC_CHILD] = newConfig;
  354. }
  355. // propagate child_execution_order upwards
  356. const visited = new Set();
  357. let current = this;
  358. while (current != null && !visited.has(current.id)) {
  359. visited.add(current.id);
  360. current.child_execution_order = Math.max(current.child_execution_order, child_execution_order);
  361. current = current.parent_run;
  362. }
  363. this.child_runs.push(child);
  364. return child;
  365. }
  366. async end(outputs, error, endTime = Date.now(), metadata) {
  367. this.outputs = this.outputs ?? outputs;
  368. this.error = this.error ?? error;
  369. this.end_time = this.end_time ?? endTime;
  370. if (metadata && Object.keys(metadata).length > 0) {
  371. this.extra = this.extra
  372. ? { ...this.extra, metadata: { ...this.extra.metadata, ...metadata } }
  373. : { metadata };
  374. }
  375. }
  376. _convertToCreate(run, runtimeEnv, excludeChildRuns = true) {
  377. const runExtra = run.extra ?? {};
  378. if (!runExtra.runtime) {
  379. runExtra.runtime = {};
  380. }
  381. if (runtimeEnv) {
  382. for (const [k, v] of Object.entries(runtimeEnv)) {
  383. if (!runExtra.runtime[k]) {
  384. runExtra.runtime[k] = v;
  385. }
  386. }
  387. }
  388. let child_runs;
  389. let parent_run_id;
  390. if (!excludeChildRuns) {
  391. child_runs = run.child_runs.map((child_run) => this._convertToCreate(child_run, runtimeEnv, excludeChildRuns));
  392. parent_run_id = undefined;
  393. }
  394. else {
  395. parent_run_id = run.parent_run?.id;
  396. child_runs = [];
  397. }
  398. const persistedRun = {
  399. id: run.id,
  400. name: run.name,
  401. start_time: run.start_time,
  402. end_time: run.end_time,
  403. run_type: run.run_type,
  404. reference_example_id: run.reference_example_id,
  405. extra: runExtra,
  406. serialized: run.serialized,
  407. error: run.error,
  408. inputs: run.inputs,
  409. outputs: run.outputs,
  410. session_name: run.project_name,
  411. child_runs: child_runs,
  412. parent_run_id: parent_run_id,
  413. trace_id: run.trace_id,
  414. dotted_order: run.dotted_order,
  415. tags: run.tags,
  416. attachments: run.attachments,
  417. };
  418. return persistedRun;
  419. }
  420. async postRun(excludeChildRuns = true) {
  421. try {
  422. const runtimeEnv = (0, env_js_1.getRuntimeEnvironment)();
  423. const runCreate = await this._convertToCreate(this, runtimeEnv, true);
  424. await this.client.createRun(runCreate);
  425. if (!excludeChildRuns) {
  426. (0, warn_js_1.warnOnce)("Posting with excludeChildRuns=false is deprecated and will be removed in a future version.");
  427. for (const childRun of this.child_runs) {
  428. await childRun.postRun(false);
  429. }
  430. }
  431. }
  432. catch (error) {
  433. console.error(`Error in postRun for run ${this.id}:`, error);
  434. }
  435. }
  436. async patchRun() {
  437. try {
  438. const runUpdate = {
  439. end_time: this.end_time,
  440. error: this.error,
  441. inputs: this.inputs,
  442. outputs: this.outputs,
  443. parent_run_id: this.parent_run?.id,
  444. reference_example_id: this.reference_example_id,
  445. extra: this.extra,
  446. events: this.events,
  447. dotted_order: this.dotted_order,
  448. trace_id: this.trace_id,
  449. tags: this.tags,
  450. attachments: this.attachments,
  451. session_name: this.project_name,
  452. };
  453. await this.client.updateRun(this.id, runUpdate);
  454. }
  455. catch (error) {
  456. console.error(`Error in patchRun for run ${this.id}`, error);
  457. }
  458. }
  459. toJSON() {
  460. return this._convertToCreate(this, undefined, false);
  461. }
  462. /**
  463. * Add an event to the run tree.
  464. * @param event - A single event or string to add
  465. */
  466. addEvent(event) {
  467. if (!this.events) {
  468. this.events = [];
  469. }
  470. if (typeof event === "string") {
  471. this.events.push({
  472. name: "event",
  473. time: new Date().toISOString(),
  474. message: event,
  475. });
  476. }
  477. else {
  478. this.events.push({
  479. ...event,
  480. time: event.time ?? new Date().toISOString(),
  481. });
  482. }
  483. }
  484. static fromRunnableConfig(parentConfig, props) {
  485. // We only handle the callback manager case for now
  486. const callbackManager = parentConfig?.callbacks;
  487. let parentRun;
  488. let projectName;
  489. let client;
  490. let tracingEnabled = (0, env_js_2.isTracingEnabled)();
  491. if (callbackManager) {
  492. const parentRunId = callbackManager?.getParentRunId?.() ?? "";
  493. const langChainTracer = callbackManager?.handlers?.find((handler) => handler?.name == "langchain_tracer");
  494. parentRun = langChainTracer?.getRun?.(parentRunId);
  495. projectName = langChainTracer?.projectName;
  496. client = langChainTracer?.client;
  497. tracingEnabled = tracingEnabled || !!langChainTracer;
  498. }
  499. if (!parentRun) {
  500. return new RunTree({
  501. ...props,
  502. client,
  503. tracingEnabled,
  504. project_name: projectName,
  505. });
  506. }
  507. const parentRunTree = new RunTree({
  508. name: parentRun.name,
  509. id: parentRun.id,
  510. trace_id: parentRun.trace_id,
  511. dotted_order: parentRun.dotted_order,
  512. client,
  513. tracingEnabled,
  514. project_name: projectName,
  515. tags: [
  516. ...new Set((parentRun?.tags ?? []).concat(parentConfig?.tags ?? [])),
  517. ],
  518. extra: {
  519. metadata: {
  520. ...parentRun?.extra?.metadata,
  521. ...parentConfig?.metadata,
  522. },
  523. },
  524. });
  525. return parentRunTree.createChild(props);
  526. }
  527. static fromDottedOrder(dottedOrder) {
  528. return this.fromHeaders({ "langsmith-trace": dottedOrder });
  529. }
  530. static fromHeaders(headers, inheritArgs) {
  531. const rawHeaders = "get" in headers && typeof headers.get === "function"
  532. ? {
  533. "langsmith-trace": headers.get("langsmith-trace"),
  534. baggage: headers.get("baggage"),
  535. }
  536. : headers;
  537. const headerTrace = rawHeaders["langsmith-trace"];
  538. if (!headerTrace || typeof headerTrace !== "string")
  539. return undefined;
  540. const parentDottedOrder = headerTrace.trim();
  541. const parsedDottedOrder = parentDottedOrder.split(".").map((part) => {
  542. const [strTime, uuid] = part.split("Z");
  543. return { strTime, time: Date.parse(strTime + "Z"), uuid };
  544. });
  545. const traceId = parsedDottedOrder[0].uuid;
  546. const config = {
  547. ...inheritArgs,
  548. name: inheritArgs?.["name"] ?? "parent",
  549. run_type: inheritArgs?.["run_type"] ?? "chain",
  550. start_time: inheritArgs?.["start_time"] ?? Date.now(),
  551. id: parsedDottedOrder.at(-1)?.uuid,
  552. trace_id: traceId,
  553. dotted_order: parentDottedOrder,
  554. };
  555. if (rawHeaders["baggage"] && typeof rawHeaders["baggage"] === "string") {
  556. const baggage = Baggage.fromHeader(rawHeaders["baggage"]);
  557. config.metadata = baggage.metadata;
  558. config.tags = baggage.tags;
  559. config.project_name = baggage.project_name;
  560. }
  561. return new RunTree(config);
  562. }
  563. toHeaders(headers) {
  564. const result = {
  565. "langsmith-trace": this.dotted_order,
  566. baggage: new Baggage(this.extra?.metadata, this.tags, this.project_name).toHeader(),
  567. };
  568. if (headers) {
  569. for (const [key, value] of Object.entries(result)) {
  570. headers.set(key, value);
  571. }
  572. }
  573. return result;
  574. }
  575. }
  576. exports.RunTree = RunTree;
  577. Object.defineProperty(RunTree, "sharedClient", {
  578. enumerable: true,
  579. configurable: true,
  580. writable: true,
  581. value: null
  582. });
  583. function isRunTree(x) {
  584. return (x !== undefined &&
  585. typeof x.createChild === "function" &&
  586. typeof x.postRun === "function");
  587. }
  588. function isLangChainTracerLike(x) {
  589. return (typeof x === "object" &&
  590. x != null &&
  591. typeof x.name === "string" &&
  592. x.name === "langchain_tracer");
  593. }
  594. function containsLangChainTracerLike(x) {
  595. return (Array.isArray(x) && x.some((callback) => isLangChainTracerLike(callback)));
  596. }
  597. function isCallbackManagerLike(x) {
  598. return (typeof x === "object" &&
  599. x != null &&
  600. Array.isArray(x.handlers));
  601. }
  602. function isRunnableConfigLike(x) {
  603. // Check that it's an object with a callbacks arg
  604. // that has either a CallbackManagerLike object with a langchain tracer within it
  605. // or an array with a LangChainTracerLike object within it
  606. return (x !== undefined &&
  607. typeof x.callbacks === "object" &&
  608. // Callback manager with a langchain tracer
  609. (containsLangChainTracerLike(x.callbacks?.handlers) ||
  610. // Or it's an array with a LangChainTracerLike object within it
  611. containsLangChainTracerLike(x.callbacks)));
  612. }