passthrough.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import { concat } from "../utils/stream.js";
  2. import { Runnable, RunnableAssign, RunnableMap, } from "./base.js";
  3. import { ensureConfig } from "./config.js";
  4. /**
  5. * A runnable to passthrough inputs unchanged or with additional keys.
  6. *
  7. * This runnable behaves almost like the identity function, except that it
  8. * can be configured to add additional keys to the output, if the input is
  9. * an object.
  10. *
  11. * The example below demonstrates how to use `RunnablePassthrough to
  12. * passthrough the input from the `.invoke()`
  13. *
  14. * @example
  15. * ```typescript
  16. * const chain = RunnableSequence.from([
  17. * {
  18. * question: new RunnablePassthrough(),
  19. * context: async () => loadContextFromStore(),
  20. * },
  21. * prompt,
  22. * llm,
  23. * outputParser,
  24. * ]);
  25. * const response = await chain.invoke(
  26. * "I can pass a single string instead of an object since I'm using `RunnablePassthrough`."
  27. * );
  28. * ```
  29. */
  30. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  31. export class RunnablePassthrough extends Runnable {
  32. static lc_name() {
  33. return "RunnablePassthrough";
  34. }
  35. constructor(fields) {
  36. super(fields);
  37. Object.defineProperty(this, "lc_namespace", {
  38. enumerable: true,
  39. configurable: true,
  40. writable: true,
  41. value: ["langchain_core", "runnables"]
  42. });
  43. Object.defineProperty(this, "lc_serializable", {
  44. enumerable: true,
  45. configurable: true,
  46. writable: true,
  47. value: true
  48. });
  49. Object.defineProperty(this, "func", {
  50. enumerable: true,
  51. configurable: true,
  52. writable: true,
  53. value: void 0
  54. });
  55. if (fields) {
  56. this.func = fields.func;
  57. }
  58. }
  59. async invoke(input, options) {
  60. const config = ensureConfig(options);
  61. if (this.func) {
  62. await this.func(input, config);
  63. }
  64. return this._callWithConfig((input) => Promise.resolve(input), input, config);
  65. }
  66. async *transform(generator, options) {
  67. const config = ensureConfig(options);
  68. let finalOutput;
  69. let finalOutputSupported = true;
  70. for await (const chunk of this._transformStreamWithConfig(generator, (input) => input, config)) {
  71. yield chunk;
  72. if (finalOutputSupported) {
  73. if (finalOutput === undefined) {
  74. finalOutput = chunk;
  75. }
  76. else {
  77. try {
  78. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  79. finalOutput = concat(finalOutput, chunk);
  80. }
  81. catch {
  82. finalOutput = undefined;
  83. finalOutputSupported = false;
  84. }
  85. }
  86. }
  87. }
  88. if (this.func && finalOutput !== undefined) {
  89. await this.func(finalOutput, config);
  90. }
  91. }
  92. /**
  93. * A runnable that assigns key-value pairs to the input.
  94. *
  95. * The example below shows how you could use it with an inline function.
  96. *
  97. * @example
  98. * ```typescript
  99. * const prompt =
  100. * PromptTemplate.fromTemplate(`Write a SQL query to answer the question using the following schema: {schema}
  101. * Question: {question}
  102. * SQL Query:`);
  103. *
  104. * // The `RunnablePassthrough.assign()` is used here to passthrough the input from the `.invoke()`
  105. * // call (in this example it's the question), along with any inputs passed to the `.assign()` method.
  106. * // In this case, we're passing the schema.
  107. * const sqlQueryGeneratorChain = RunnableSequence.from([
  108. * RunnablePassthrough.assign({
  109. * schema: async () => db.getTableInfo(),
  110. * }),
  111. * prompt,
  112. * new ChatOpenAI({}).withConfig({ stop: ["\nSQLResult:"] }),
  113. * new StringOutputParser(),
  114. * ]);
  115. * const result = await sqlQueryGeneratorChain.invoke({
  116. * question: "How many employees are there?",
  117. * });
  118. * ```
  119. */
  120. static assign(mapping) {
  121. return new RunnableAssign(new RunnableMap({ steps: mapping }));
  122. }
  123. }