Implement new serialization format, currently working for all llms, chat models and prompts, and some chains

Serialization improvements
This commit is contained in:
Nuno Campos
2023-05-26 19:44:44 +01:00
parent 2835c13398
commit fb60a1a900
33 changed files with 1255 additions and 30 deletions
+3
View File
@@ -58,6 +58,9 @@ module.exports = {
"no-return-await": 0,
"consistent-return": 0,
"no-else-return": 0,
"func-names": 0,
"no-lonely-if": 0,
"prefer-rest-params": 0,
"new-cap": ["error", { properties: false, capIsNew: false }],
},
};
+3
View File
@@ -1,3 +1,6 @@
load.cjs
load.js
load.d.ts
agents.cjs
agents.js
agents.d.ts
+9 -1
View File
@@ -10,6 +10,9 @@
"types": "./index.d.ts",
"files": [
"dist/",
"load.cjs",
"load.js",
"load.d.ts",
"agents.cjs",
"agents.js",
"agents.d.ts",
@@ -404,7 +407,7 @@
"lint": "eslint src && dpdm --exit-code circular:1 --no-warning --no-tree src/*.ts src/**/*.ts",
"lint:fix": "yarn lint --fix",
"precommit": "tsc --noEmit && lint-staged",
"clean": "rm -rf dist/ && node scripts/create-entrypoints.js clean",
"clean": "rm -rf dist/ && node scripts/create-entrypoints.js pre",
"prepack": "yarn build",
"release": "release-it --only-version --config .release-it.json",
"test": "NODE_OPTIONS=--experimental-vm-modules jest --testPathIgnorePatterns=\\.int\\.test.ts --testTimeout 30000",
@@ -728,6 +731,11 @@
"import": "./index.js",
"require": "./index.cjs"
},
"./load": {
"types": "./load.d.ts",
"import": "./load.js",
"require": "./load.cjs"
},
"./agents": {
"types": "./agents.d.ts",
"import": "./agents.js",
+81 -1
View File
@@ -7,6 +7,7 @@ import * as path from "path";
// This is used to generate the `exports` field in package.json.
// Order is not important.
const entrypoints = {
load: "load/index",
// agents
agents: "agents/index",
"agents/load": "agents/load",
@@ -373,10 +374,89 @@ const cleanGenerated = () => {
});
};
// Tuple describing the auto-generated import map (used by langchain/load)
// [package name, import statement, import map path]
// This will not include entrypoints deprecated or requiring optional deps.
const importMap = [
"langchain",
(k, p) => `export * as ${k.replace(/\//g, "__")} from "../${p}.js";`,
"src/load/import_map.ts",
];
const generateImportMap = () => {
// Generate import map
const entrypointsToInclude = Object.keys(entrypoints)
.filter((key) => key !== "load")
.filter((key) => !deprecatedNodeOnly.includes(key))
.filter((key) => !requiresOptionalDependency.includes(key));
const [pkg, importStatement, importMapPath] = importMap;
const contents =
entrypointsToInclude
.map((key) => importStatement(key, entrypoints[key]))
.join("\n") + "\n";
fs.writeFileSync(
`../${pkg}/${importMapPath}`,
"// Auto-generated by `scripts/create-entrypoints.js`. Do not edit manually.\n\n" +
contents
);
};
const importTypes = [
"langchain",
(k) =>
` "langchain/${k}"?:
| typeof import("../${k}.js")
| Promise<typeof import("../${k}.js")>;`,
"src/load/import_type.d.ts",
];
const generateImportTypes = () => {
// Generate import types
const entrypointsToInclude = Object.keys(entrypoints)
.filter((key) => !deprecatedNodeOnly.includes(key))
.filter((key) => requiresOptionalDependency.includes(key));
const [pkg, importStatement, importTypesPath] = importTypes;
const contents =
entrypointsToInclude
.map((key) => importStatement(key, entrypoints[key]))
.join("\n") + "\n}\n";
fs.writeFileSync(
`../${pkg}/${importTypesPath}`,
"// Auto-generated by `scripts/create-entrypoints.js`. Do not edit manually.\n\nexport interface OptionalImportMap {\n" +
contents
);
};
const importConstants = [
"langchain",
(k) => ` "langchain/${k}"`,
"src/load/import_constants.ts",
];
const generateImportConstants = () => {
// Generate import constants
const entrypointsToInclude = Object.keys(entrypoints)
.filter((key) => !deprecatedNodeOnly.includes(key))
.filter((key) => requiresOptionalDependency.includes(key));
const [pkg, importStatement, importConstantsPath] = importConstants;
const contents =
entrypointsToInclude
.map((key) => importStatement(key, entrypoints[key]))
.join(",\n") + "\n]\n";
fs.writeFileSync(
`../${pkg}/${importConstantsPath}`,
"// Auto-generated by `scripts/create-entrypoints.js`. Do not edit manually.\n\nexport const optionalImportEntrypoints = [\n" +
contents
);
};
const command = process.argv[2];
if (command === "clean") {
if (command === "pre") {
cleanGenerated();
generateImportMap();
generateImportTypes();
generateImportConstants();
} else {
updateConfig();
}
+13 -4
View File
@@ -8,6 +8,7 @@ import { CallbackManager, Callbacks } from "../callbacks/manager.js";
import { AsyncCaller, AsyncCallerParams } from "../util/async_caller.js";
import { getModelNameForTiktoken } from "./count_tokens.js";
import { encodingForModel } from "../util/tiktoken.js";
import { Serializable } from "../schema/load.js";
const getVerbosity = () => false;
@@ -25,7 +26,10 @@ export interface BaseLangChainParams {
/**
* Base class for language models, chains, tools.
*/
export abstract class BaseLangChain implements BaseLangChainParams {
export abstract class BaseLangChain
extends Serializable
implements BaseLangChainParams
{
/**
* Whether to print out response text.
*/
@@ -34,6 +38,7 @@ export abstract class BaseLangChain implements BaseLangChainParams {
callbacks?: Callbacks;
constructor(params: BaseLangChainParams) {
super(params);
this.verbose = params.verbose ?? getVerbosity();
this.callbacks = params.callbacks;
}
@@ -94,10 +99,14 @@ export abstract class BaseLanguageModel
*/
caller: AsyncCaller;
constructor(params: BaseLanguageModelParams) {
constructor({
callbacks,
callbackManager,
...params
}: BaseLanguageModelParams) {
super({
verbose: params.verbose,
callbacks: params.callbacks ?? params.callbackManager,
callbacks: callbacks ?? callbackManager,
...params,
});
this.caller = new AsyncCaller(params ?? {});
}
+15 -1
View File
@@ -6,6 +6,7 @@ import {
ChainValues,
LLMResult,
} from "../schema/index.js";
import { Serializable, Serialized } from "../schema/load.js";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type Error = any;
@@ -166,8 +167,16 @@ export type CallbackHandlerMethods = BaseCallbackHandlerMethodsClass;
export abstract class BaseCallbackHandler
extends BaseCallbackHandlerMethodsClass
implements BaseCallbackHandlerInput
implements BaseCallbackHandlerInput, Serializable
{
lc_namespace = ["langchain", "callbacks"];
get lc_name() {
return this.name;
}
lc_arguments: unknown[];
abstract name: string;
ignoreLLM = false;
@@ -184,6 +193,7 @@ export abstract class BaseCallbackHandler
constructor(input?: BaseCallbackHandlerInput) {
super();
this.lc_arguments = [input];
if (input) {
this.ignoreLLM = input.ignoreLLM ?? this.ignoreLLM;
this.ignoreChain = input.ignoreChain ?? this.ignoreChain;
@@ -197,6 +207,10 @@ export abstract class BaseCallbackHandler
) => BaseCallbackHandler)(this);
}
toJSON(): Serialized {
return Serializable.prototype.toJSON.call(this);
}
static fromMethods(methods: CallbackHandlerMethods) {
class Handler extends BaseCallbackHandler {
name = uuid.v4();
+3 -3
View File
@@ -6,7 +6,7 @@ import {
RunInputs,
RunOutputs,
} from "../../schema/index.js";
import { BaseCallbackHandler } from "../base.js";
import { BaseCallbackHandler, BaseCallbackHandlerInput } from "../base.js";
export type RunType = "llm" | "chain" | "tool";
@@ -40,8 +40,8 @@ export interface AgentRun extends Run {
export abstract class BaseTracer extends BaseCallbackHandler {
protected runMap: Map<string, Run> = new Map();
constructor() {
super();
constructor(_fields?: BaseCallbackHandlerInput) {
super(...arguments);
}
copy(): this {
@@ -5,8 +5,9 @@ import {
getRuntimeEnvironment,
} from "../../util/env.js";
import { BaseTracer } from "./tracer.js";
import { BaseCallbackHandlerInput } from "../base.js";
export interface LangChainTracerFields {
export interface LangChainTracerFields extends BaseCallbackHandlerInput {
exampleId?: string;
sessionName?: string;
client?: LangChainPlusClient;
@@ -24,8 +25,9 @@ export class LangChainTracer
client: LangChainPlusClient;
constructor({ exampleId, sessionName, client }: LangChainTracerFields = {}) {
super();
constructor(fields: LangChainTracerFields = {}) {
super(fields);
const { exampleId, sessionName, client } = fields;
this.sessionName =
sessionName ?? getEnvironmentVariable("LANGCHAIN_SESSION");
+8
View File
@@ -26,6 +26,14 @@ export interface ChainInputs extends BaseLangChainParams {
export abstract class BaseChain extends BaseLangChain implements ChainInputs {
declare memory?: BaseMemory;
get lc_namespace(): ["langchain", "chains"] {
return ["langchain", "chains"];
}
get lc_name(): string {
return this._chainType();
}
constructor(
fields?: BaseMemory | ChainInputs,
/** @deprecated */
+6
View File
@@ -41,6 +41,12 @@ export abstract class BaseChatModel extends BaseLanguageModel {
declare ParsedCallOptions: Omit<this["CallOptions"], "timeout">;
lc_namespace = ["langchain", "chat_models"];
get lc_name(): string {
return this._llmType();
}
constructor(fields: BaseChatModelParams) {
super(fields);
}
+6
View File
@@ -44,6 +44,12 @@ export abstract class BaseLLM extends BaseLanguageModel {
declare ParsedCallOptions: Omit<this["CallOptions"], "timeout">;
lc_namespace = ["langchain", "llms"];
get lc_name(): string {
return this._llmType();
}
cache?: BaseCache;
constructor({ cache, concurrency, ...rest }: BaseLLMParams) {
+1 -1
View File
@@ -60,7 +60,7 @@ export class HuggingFaceInference extends LLM implements HFInput {
}
_llmType() {
return "huggingface_hub";
return "hf";
}
/** @ignore */
+1 -1
View File
@@ -379,7 +379,7 @@ export class OpenAIChat
}
_llmType() {
return "openai";
return "openai-chat";
}
}
+67
View File
@@ -0,0 +1,67 @@
// Auto-generated by `scripts/create-entrypoints.js`. Do not edit manually.
export const optionalImportEntrypoints = [
"langchain/agents/load",
"langchain/tools/aws_lambda",
"langchain/tools/calculator",
"langchain/tools/webbrowser",
"langchain/chains/load",
"langchain/chains/query_constructor",
"langchain/chains/query_constructor/ir",
"langchain/embeddings/cohere",
"langchain/embeddings/tensorflow",
"langchain/embeddings/hf",
"langchain/embeddings/googlevertexai",
"langchain/llms/load",
"langchain/llms/cohere",
"langchain/llms/hf",
"langchain/llms/replicate",
"langchain/llms/googlevertexai",
"langchain/llms/sagemaker_endpoint",
"langchain/prompts/load",
"langchain/vectorstores/chroma",
"langchain/vectorstores/hnswlib",
"langchain/vectorstores/faiss",
"langchain/vectorstores/weaviate",
"langchain/vectorstores/mongo",
"langchain/vectorstores/pinecone",
"langchain/vectorstores/qdrant",
"langchain/vectorstores/supabase",
"langchain/vectorstores/opensearch",
"langchain/vectorstores/milvus",
"langchain/vectorstores/myscale",
"langchain/vectorstores/redis",
"langchain/document_loaders/web/apify_dataset",
"langchain/document_loaders/web/cheerio",
"langchain/document_loaders/web/puppeteer",
"langchain/document_loaders/web/playwright",
"langchain/document_loaders/web/college_confidential",
"langchain/document_loaders/web/gitbook",
"langchain/document_loaders/web/hn",
"langchain/document_loaders/web/imsdb",
"langchain/document_loaders/web/github",
"langchain/document_loaders/web/s3",
"langchain/document_loaders/web/confluence",
"langchain/document_loaders/fs/directory",
"langchain/document_loaders/fs/buffer",
"langchain/document_loaders/fs/text",
"langchain/document_loaders/fs/json",
"langchain/document_loaders/fs/srt",
"langchain/document_loaders/fs/pdf",
"langchain/document_loaders/fs/docx",
"langchain/document_loaders/fs/epub",
"langchain/document_loaders/fs/csv",
"langchain/document_loaders/fs/notion",
"langchain/document_loaders/fs/unstructured",
"langchain/chat_models/googlevertexai",
"langchain/sql_db",
"langchain/output_parsers/expression",
"langchain/retrievers/supabase",
"langchain/retrievers/metal",
"langchain/retrievers/self_query",
"langchain/cache/redis",
"langchain/stores/file/node",
"langchain/stores/message/dynamodb",
"langchain/stores/message/redis",
"langchain/stores/message/upstash_redis"
]
+41
View File
@@ -0,0 +1,41 @@
// Auto-generated by `scripts/create-entrypoints.js`. Do not edit manually.
export * as agents from "../agents/index.js";
export * as base_language from "../base_language/index.js";
export * as tools from "../tools/index.js";
export * as chains from "../chains/index.js";
export * as embeddings__base from "../embeddings/base.js";
export * as embeddings__fake from "../embeddings/fake.js";
export * as embeddings__openai from "../embeddings/openai.js";
export * as llms__base from "../llms/base.js";
export * as llms__openai from "../llms/openai.js";
export * as prompts from "../prompts/index.js";
export * as vectorstores__base from "../vectorstores/base.js";
export * as vectorstores__memory from "../vectorstores/memory.js";
export * as vectorstores__prisma from "../vectorstores/prisma.js";
export * as text_splitter from "../text_splitter.js";
export * as memory from "../memory/index.js";
export * as document from "../document.js";
export * as docstore from "../docstore/index.js";
export * as document_loaders__base from "../document_loaders/base.js";
export * as chat_models__base from "../chat_models/base.js";
export * as chat_models__openai from "../chat_models/openai.js";
export * as chat_models__anthropic from "../chat_models/anthropic.js";
export * as schema from "../schema/index.js";
export * as schema__output_parser from "../schema/output_parser.js";
export * as schema__query_constructor from "../schema/query_constructor.js";
export * as callbacks from "../callbacks/index.js";
export * as output_parsers from "../output_parsers/index.js";
export * as retrievers__remote from "../retrievers/remote/index.js";
export * as retrievers__databerry from "../retrievers/databerry.js";
export * as retrievers__contextual_compression from "../retrievers/contextual_compression.js";
export * as retrievers__document_compressors from "../retrievers/document_compressors/index.js";
export * as retrievers__time_weighted from "../retrievers/time_weighted.js";
export * as retrievers__document_compressors__chain_extract from "../retrievers/document_compressors/chain_extract.js";
export * as retrievers__hyde from "../retrievers/hyde.js";
export * as cache from "../cache/index.js";
export * as stores__file__in_memory from "../stores/file/in_memory.js";
export * as experimental__autogpt from "../experimental/autogpt/index.js";
export * as experimental__babyagi from "../experimental/babyagi/index.js";
export * as experimental__plan_and_execute from "../experimental/plan_and_execute/index.js";
export * as client from "../client/index.js";
+193
View File
@@ -0,0 +1,193 @@
// Auto-generated by `scripts/create-entrypoints.js`. Do not edit manually.
export interface OptionalImportMap {
"langchain/agents/load"?:
| typeof import("../agents/load.js")
| Promise<typeof import("../agents/load.js")>;
"langchain/tools/aws_lambda"?:
| typeof import("../tools/aws_lambda.js")
| Promise<typeof import("../tools/aws_lambda.js")>;
"langchain/tools/calculator"?:
| typeof import("../tools/calculator.js")
| Promise<typeof import("../tools/calculator.js")>;
"langchain/tools/webbrowser"?:
| typeof import("../tools/webbrowser.js")
| Promise<typeof import("../tools/webbrowser.js")>;
"langchain/chains/load"?:
| typeof import("../chains/load.js")
| Promise<typeof import("../chains/load.js")>;
"langchain/chains/query_constructor"?:
| typeof import("../chains/query_constructor.js")
| Promise<typeof import("../chains/query_constructor.js")>;
"langchain/chains/query_constructor/ir"?:
| typeof import("../chains/query_constructor/ir.js")
| Promise<typeof import("../chains/query_constructor/ir.js")>;
"langchain/embeddings/cohere"?:
| typeof import("../embeddings/cohere.js")
| Promise<typeof import("../embeddings/cohere.js")>;
"langchain/embeddings/tensorflow"?:
| typeof import("../embeddings/tensorflow.js")
| Promise<typeof import("../embeddings/tensorflow.js")>;
"langchain/embeddings/hf"?:
| typeof import("../embeddings/hf.js")
| Promise<typeof import("../embeddings/hf.js")>;
"langchain/embeddings/googlevertexai"?:
| typeof import("../embeddings/googlevertexai.js")
| Promise<typeof import("../embeddings/googlevertexai.js")>;
"langchain/llms/load"?:
| typeof import("../llms/load.js")
| Promise<typeof import("../llms/load.js")>;
"langchain/llms/cohere"?:
| typeof import("../llms/cohere.js")
| Promise<typeof import("../llms/cohere.js")>;
"langchain/llms/hf"?:
| typeof import("../llms/hf.js")
| Promise<typeof import("../llms/hf.js")>;
"langchain/llms/replicate"?:
| typeof import("../llms/replicate.js")
| Promise<typeof import("../llms/replicate.js")>;
"langchain/llms/googlevertexai"?:
| typeof import("../llms/googlevertexai.js")
| Promise<typeof import("../llms/googlevertexai.js")>;
"langchain/llms/sagemaker_endpoint"?:
| typeof import("../llms/sagemaker_endpoint.js")
| Promise<typeof import("../llms/sagemaker_endpoint.js")>;
"langchain/prompts/load"?:
| typeof import("../prompts/load.js")
| Promise<typeof import("../prompts/load.js")>;
"langchain/vectorstores/chroma"?:
| typeof import("../vectorstores/chroma.js")
| Promise<typeof import("../vectorstores/chroma.js")>;
"langchain/vectorstores/hnswlib"?:
| typeof import("../vectorstores/hnswlib.js")
| Promise<typeof import("../vectorstores/hnswlib.js")>;
"langchain/vectorstores/faiss"?:
| typeof import("../vectorstores/faiss.js")
| Promise<typeof import("../vectorstores/faiss.js")>;
"langchain/vectorstores/weaviate"?:
| typeof import("../vectorstores/weaviate.js")
| Promise<typeof import("../vectorstores/weaviate.js")>;
"langchain/vectorstores/mongo"?:
| typeof import("../vectorstores/mongo.js")
| Promise<typeof import("../vectorstores/mongo.js")>;
"langchain/vectorstores/pinecone"?:
| typeof import("../vectorstores/pinecone.js")
| Promise<typeof import("../vectorstores/pinecone.js")>;
"langchain/vectorstores/qdrant"?:
| typeof import("../vectorstores/qdrant.js")
| Promise<typeof import("../vectorstores/qdrant.js")>;
"langchain/vectorstores/supabase"?:
| typeof import("../vectorstores/supabase.js")
| Promise<typeof import("../vectorstores/supabase.js")>;
"langchain/vectorstores/opensearch"?:
| typeof import("../vectorstores/opensearch.js")
| Promise<typeof import("../vectorstores/opensearch.js")>;
"langchain/vectorstores/milvus"?:
| typeof import("../vectorstores/milvus.js")
| Promise<typeof import("../vectorstores/milvus.js")>;
"langchain/vectorstores/myscale"?:
| typeof import("../vectorstores/myscale.js")
| Promise<typeof import("../vectorstores/myscale.js")>;
"langchain/vectorstores/redis"?:
| typeof import("../vectorstores/redis.js")
| Promise<typeof import("../vectorstores/redis.js")>;
"langchain/document_loaders/web/apify_dataset"?:
| typeof import("../document_loaders/web/apify_dataset.js")
| Promise<typeof import("../document_loaders/web/apify_dataset.js")>;
"langchain/document_loaders/web/cheerio"?:
| typeof import("../document_loaders/web/cheerio.js")
| Promise<typeof import("../document_loaders/web/cheerio.js")>;
"langchain/document_loaders/web/puppeteer"?:
| typeof import("../document_loaders/web/puppeteer.js")
| Promise<typeof import("../document_loaders/web/puppeteer.js")>;
"langchain/document_loaders/web/playwright"?:
| typeof import("../document_loaders/web/playwright.js")
| Promise<typeof import("../document_loaders/web/playwright.js")>;
"langchain/document_loaders/web/college_confidential"?:
| typeof import("../document_loaders/web/college_confidential.js")
| Promise<typeof import("../document_loaders/web/college_confidential.js")>;
"langchain/document_loaders/web/gitbook"?:
| typeof import("../document_loaders/web/gitbook.js")
| Promise<typeof import("../document_loaders/web/gitbook.js")>;
"langchain/document_loaders/web/hn"?:
| typeof import("../document_loaders/web/hn.js")
| Promise<typeof import("../document_loaders/web/hn.js")>;
"langchain/document_loaders/web/imsdb"?:
| typeof import("../document_loaders/web/imsdb.js")
| Promise<typeof import("../document_loaders/web/imsdb.js")>;
"langchain/document_loaders/web/github"?:
| typeof import("../document_loaders/web/github.js")
| Promise<typeof import("../document_loaders/web/github.js")>;
"langchain/document_loaders/web/s3"?:
| typeof import("../document_loaders/web/s3.js")
| Promise<typeof import("../document_loaders/web/s3.js")>;
"langchain/document_loaders/web/confluence"?:
| typeof import("../document_loaders/web/confluence.js")
| Promise<typeof import("../document_loaders/web/confluence.js")>;
"langchain/document_loaders/fs/directory"?:
| typeof import("../document_loaders/fs/directory.js")
| Promise<typeof import("../document_loaders/fs/directory.js")>;
"langchain/document_loaders/fs/buffer"?:
| typeof import("../document_loaders/fs/buffer.js")
| Promise<typeof import("../document_loaders/fs/buffer.js")>;
"langchain/document_loaders/fs/text"?:
| typeof import("../document_loaders/fs/text.js")
| Promise<typeof import("../document_loaders/fs/text.js")>;
"langchain/document_loaders/fs/json"?:
| typeof import("../document_loaders/fs/json.js")
| Promise<typeof import("../document_loaders/fs/json.js")>;
"langchain/document_loaders/fs/srt"?:
| typeof import("../document_loaders/fs/srt.js")
| Promise<typeof import("../document_loaders/fs/srt.js")>;
"langchain/document_loaders/fs/pdf"?:
| typeof import("../document_loaders/fs/pdf.js")
| Promise<typeof import("../document_loaders/fs/pdf.js")>;
"langchain/document_loaders/fs/docx"?:
| typeof import("../document_loaders/fs/docx.js")
| Promise<typeof import("../document_loaders/fs/docx.js")>;
"langchain/document_loaders/fs/epub"?:
| typeof import("../document_loaders/fs/epub.js")
| Promise<typeof import("../document_loaders/fs/epub.js")>;
"langchain/document_loaders/fs/csv"?:
| typeof import("../document_loaders/fs/csv.js")
| Promise<typeof import("../document_loaders/fs/csv.js")>;
"langchain/document_loaders/fs/notion"?:
| typeof import("../document_loaders/fs/notion.js")
| Promise<typeof import("../document_loaders/fs/notion.js")>;
"langchain/document_loaders/fs/unstructured"?:
| typeof import("../document_loaders/fs/unstructured.js")
| Promise<typeof import("../document_loaders/fs/unstructured.js")>;
"langchain/chat_models/googlevertexai"?:
| typeof import("../chat_models/googlevertexai.js")
| Promise<typeof import("../chat_models/googlevertexai.js")>;
"langchain/sql_db"?:
| typeof import("../sql_db.js")
| Promise<typeof import("../sql_db.js")>;
"langchain/output_parsers/expression"?:
| typeof import("../output_parsers/expression.js")
| Promise<typeof import("../output_parsers/expression.js")>;
"langchain/retrievers/supabase"?:
| typeof import("../retrievers/supabase.js")
| Promise<typeof import("../retrievers/supabase.js")>;
"langchain/retrievers/metal"?:
| typeof import("../retrievers/metal.js")
| Promise<typeof import("../retrievers/metal.js")>;
"langchain/retrievers/self_query"?:
| typeof import("../retrievers/self_query.js")
| Promise<typeof import("../retrievers/self_query.js")>;
"langchain/cache/redis"?:
| typeof import("../cache/redis.js")
| Promise<typeof import("../cache/redis.js")>;
"langchain/stores/file/node"?:
| typeof import("../stores/file/node.js")
| Promise<typeof import("../stores/file/node.js")>;
"langchain/stores/message/dynamodb"?:
| typeof import("../stores/message/dynamodb.js")
| Promise<typeof import("../stores/message/dynamodb.js")>;
"langchain/stores/message/redis"?:
| typeof import("../stores/message/redis.js")
| Promise<typeof import("../stores/message/redis.js")>;
"langchain/stores/message/upstash_redis"?:
| typeof import("../stores/message/upstash_redis.js")
| Promise<typeof import("../stores/message/upstash_redis.js")>;
}
+118
View File
@@ -0,0 +1,118 @@
import { Serialized } from "../schema/load.js";
import { optionalImportEntrypoints } from "./import_constants.js";
import * as importMap from "./import_map.js";
import { OptionalImportMap } from "./import_type.js";
async function reviver(
this: OptionalImportMap,
value: unknown
): Promise<unknown> {
if (
typeof value === "object" &&
value !== null &&
!Array.isArray(value) &&
"v" in value &&
"type" in value &&
"identifier" in value &&
"arguments" in value &&
value.v === 1
) {
const serialized = value as Serialized;
const str = JSON.stringify(serialized);
const [name, ...namespaceReverse] = serialized.identifier.slice().reverse();
const namespace = namespaceReverse.reverse();
let module:
| (typeof importMap)[keyof typeof importMap]
| OptionalImportMap[keyof OptionalImportMap];
if (
optionalImportEntrypoints.includes(namespace.join("/")) ||
namespace.join("/") in this
) {
if (namespace.join("/") in this) {
module = await this[namespace.join("/") as keyof typeof this];
} else {
throw new Error(
`Missing key "${namespace.join("/")}" in 2nd argument to load()`
);
}
} else {
// Currently, we only support langchain imports.
if (namespace[0] === "langchain") {
namespace.shift();
} else {
throw new Error(`Invalid namespace: ${str}`);
}
// The root namespace "langchain" is not a valid import.
if (namespace.length === 0) {
throw new Error(`Invalid namespace: ${str}`);
}
// Find the longest matching namespace.
let importMapKey: string;
do {
importMapKey = namespace.join("__");
if (importMapKey in importMap) {
break;
} else {
namespace.pop();
}
} while (namespace.length > 0);
// If no matching namespace is found, throw an error.
if (importMapKey in importMap) {
module = importMap[importMapKey as keyof typeof importMap];
} else {
throw new Error(`Invalid namespace: ${str}`);
}
}
// Extract the builder from the import map.
const builder = module[name as keyof typeof module];
if (typeof builder !== "function") {
throw new Error(`Invalid identifer: ${str}`);
}
// Recurse on the arguments, which may be serialized objects themselves
const args = await Promise.all(serialized.arguments.map(reviver, this));
// Construct the object
if (serialized.type === "constructor") {
// eslint-disable-next-line new-cap, @typescript-eslint/no-explicit-any
const instance = new (builder as any)(...args);
const fields = serialized.fields
? await reviver.call(this, serialized.fields)
: undefined;
Object.assign(instance, fields);
return instance;
} else if (serialized.type === "function") {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (builder as any)(...args);
} else {
throw new Error(`Invalid type: ${str}`);
}
} else if (typeof value === "object" && value !== null) {
if (Array.isArray(value)) {
return Promise.all(value.map(reviver, this));
} else {
return Object.fromEntries(
await Promise.all(
Object.entries(value).map(async ([key, value]) => [
key,
await reviver.call(this, value),
])
)
);
}
}
return value;
}
export async function load<T>(
text: string,
optionalImportsMap: OptionalImportMap = {}
): Promise<T> {
const json = JSON.parse(text);
return reviver.call(optionalImportsMap, json) as Promise<T>;
}
+580
View File
@@ -0,0 +1,580 @@
import { test, expect } from "@jest/globals";
import { load } from "../index.js";
import { OpenAI } from "../../llms/openai.js";
import { PromptTemplate } from "../../prompts/prompt.js";
import { LLMChain } from "../../chains/llm_chain.js";
import { Cohere } from "../../llms/cohere.js";
import {
HumanMessagePromptTemplate,
SystemMessagePromptTemplate,
ChatPromptTemplate,
} from "../../prompts/chat.js";
import { ChatOpenAI } from "../../chat_models/openai.js";
import { LangChainTracer } from "../../callbacks/index.js";
import {
FewShotPromptTemplate,
LengthBasedExampleSelector,
} from "../../prompts/index.js";
test("serialize + deserialize llm", async () => {
const llm = new OpenAI({ temperature: 0.5, modelName: "davinci" });
const str = JSON.stringify(llm, null, 2);
expect(str).toMatchInlineSnapshot(`
"{
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"llms",
"openai",
"OpenAI"
],
"arguments": [
{
"temperature": 0.5,
"modelName": "davinci"
}
]
}"
`);
const llm2 = await load<OpenAI>(str);
expect(llm2).toBeInstanceOf(OpenAI);
expect(JSON.stringify(llm2, null, 2)).toBe(str);
});
test("serialize + deserialize llm with optional deps", async () => {
const llm = new Cohere({ temperature: 0.5 });
const str = JSON.stringify(llm, null, 2);
expect(str).toMatchInlineSnapshot(`
"{
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"llms",
"cohere",
"Cohere"
],
"arguments": [
{
"temperature": 0.5
}
]
}"
`);
const llm2 = await load<Cohere>(str, {
"langchain/llms/cohere": { Cohere },
});
expect(llm2).toBeInstanceOf(Cohere);
expect(JSON.stringify(llm2, null, 2)).toBe(str);
const llm3 = await load<Cohere>(str, {
"langchain/llms/cohere": import("../../llms/cohere.js"),
});
expect(llm3).toBeInstanceOf(Cohere);
expect(JSON.stringify(llm3, null, 2)).toBe(str);
});
test("serialize + deserialize llm chain string prompt", async () => {
const llm = new OpenAI({
temperature: 0.5,
modelName: "davinci",
verbose: true,
callbacks: [
new LangChainTracer(),
// This custom handler is not serialized
{
handleLLMEnd(output) {
console.log(output);
},
},
],
});
const prompt = PromptTemplate.fromTemplate("Hello, {name}!");
const chain = new LLMChain({ llm, prompt });
const str = JSON.stringify(chain, null, 2);
expect(str).toMatchInlineSnapshot(`
"{
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"chains",
"llm_chain",
"LLMChain"
],
"arguments": [
{
"llm": {
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"llms",
"openai",
"OpenAI"
],
"arguments": [
{
"callbacks": [
{
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"callbacks",
"langchain_tracer",
"LangChainTracer"
],
"arguments": [
{}
]
},
{}
],
"temperature": 0.5,
"modelName": "davinci",
"verbose": true
}
]
},
"prompt": {
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"prompts",
"prompt",
"PromptTemplate"
],
"arguments": [
{
"inputVariables": [
"name"
],
"templateFormat": "f-string",
"template": "Hello, {name}!"
}
]
}
}
]
}"
`);
const chain2 = await load<LLMChain>(str);
expect(chain2).toBeInstanceOf(LLMChain);
expect(JSON.stringify(chain2, null, 2)).toBe(str);
});
test("serialize + deserialize llm chain chat prompt", async () => {
const llm = new ChatOpenAI({
temperature: 0.5,
modelName: "gpt-4",
streaming: true,
prefixMessages: [
{
role: "system",
content: "You're a nice assistant",
},
],
});
const prompt = ChatPromptTemplate.fromPromptMessages([
SystemMessagePromptTemplate.fromTemplate("You are talking to {name}."),
HumanMessagePromptTemplate.fromTemplate("Hello, nice model."),
]);
const chain = new LLMChain({ llm, prompt });
const str = JSON.stringify(chain, null, 2);
expect(str).toMatchInlineSnapshot(`
"{
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"chains",
"llm_chain",
"LLMChain"
],
"arguments": [
{
"llm": {
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"chat_models",
"openai",
"ChatOpenAI"
],
"arguments": [
{
"temperature": 0.5,
"modelName": "gpt-4",
"streaming": true,
"prefixMessages": [
{
"role": "system",
"content": "You're a nice assistant"
}
]
}
]
},
"prompt": {
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"prompts",
"chat",
"ChatPromptTemplate"
],
"arguments": [
{
"inputVariables": [
"name"
],
"promptMessages": [
{
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"prompts",
"chat",
"SystemMessagePromptTemplate"
],
"arguments": [
{
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"prompts",
"prompt",
"PromptTemplate"
],
"arguments": [
{
"inputVariables": [
"name"
],
"templateFormat": "f-string",
"template": "You are talking to {name}."
}
]
}
]
},
{
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"prompts",
"chat",
"HumanMessagePromptTemplate"
],
"arguments": [
{
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"prompts",
"prompt",
"PromptTemplate"
],
"arguments": [
{
"inputVariables": [],
"templateFormat": "f-string",
"template": "Hello, nice model."
}
]
}
]
}
],
"partialVariables": {}
}
]
}
}
]
}"
`);
const chain2 = await load<LLMChain>(str);
expect(chain2).toBeInstanceOf(LLMChain);
expect(JSON.stringify(chain2, null, 2)).toBe(str);
});
test("serialize + deserialize llm chain few shot prompt w/ examples", async () => {
const llm = new OpenAI({
temperature: 0.5,
modelName: "davinci",
callbacks: [new LangChainTracer()],
});
const prompt = new FewShotPromptTemplate({
examples: [{ yo: "1" }, { yo: "2" }],
prefix: "You are a nice assistant",
examplePrompt: PromptTemplate.fromTemplate("An example about {yo}"),
suffix: "My name is {name}",
inputVariables: ["yo", "name"],
});
const chain = new LLMChain({ llm, prompt });
const str = JSON.stringify(chain, null, 2);
expect(str).toMatchInlineSnapshot(`
"{
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"chains",
"llm_chain",
"LLMChain"
],
"arguments": [
{
"llm": {
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"llms",
"openai",
"OpenAI"
],
"arguments": [
{
"callbacks": [
{
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"callbacks",
"langchain_tracer",
"LangChainTracer"
],
"arguments": [
{}
]
}
],
"temperature": 0.5,
"modelName": "davinci"
}
]
},
"prompt": {
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"prompts",
"few_shot",
"FewShotPromptTemplate"
],
"arguments": [
{
"examples": [
{
"yo": "1"
},
{
"yo": "2"
}
],
"prefix": "You are a nice assistant",
"examplePrompt": {
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"prompts",
"prompt",
"PromptTemplate"
],
"arguments": [
{
"inputVariables": [
"yo"
],
"templateFormat": "f-string",
"template": "An example about {yo}"
}
]
},
"suffix": "My name is {name}",
"inputVariables": [
"yo",
"name"
]
}
]
}
}
]
}"
`);
const chain2 = await load<LLMChain>(str);
expect(chain2).toBeInstanceOf(LLMChain);
expect(JSON.stringify(chain2, null, 2)).toBe(str);
});
test("serialize + deserialize llm chain few shot prompt w/ selector", async () => {
const llm = new OpenAI({
temperature: 0.5,
modelName: "davinci",
callbacks: [new LangChainTracer()],
});
const examplePrompt = PromptTemplate.fromTemplate("An example about {yo}");
const prompt = new FewShotPromptTemplate({
exampleSelector: await LengthBasedExampleSelector.fromExamples(
[{ yo: "1" }, { yo: "2" }],
{ examplePrompt }
),
prefix: "You are a nice assistant",
examplePrompt,
suffix: "My name is {name}",
inputVariables: ["yo", "name"],
});
const chain = new LLMChain({ llm, prompt });
const str = JSON.stringify(chain, null, 2);
expect(str).toMatchInlineSnapshot(`
"{
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"chains",
"llm_chain",
"LLMChain"
],
"arguments": [
{
"llm": {
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"llms",
"openai",
"OpenAI"
],
"arguments": [
{
"callbacks": [
{
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"callbacks",
"langchain_tracer",
"LangChainTracer"
],
"arguments": [
{}
]
}
],
"temperature": 0.5,
"modelName": "davinci"
}
]
},
"prompt": {
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"prompts",
"few_shot",
"FewShotPromptTemplate"
],
"arguments": [
{
"exampleSelector": {
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"prompts",
"selectors",
"LengthBasedExampleSelector"
],
"arguments": [
{
"examplePrompt": {
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"prompts",
"prompt",
"PromptTemplate"
],
"arguments": [
{
"inputVariables": [
"yo"
],
"templateFormat": "f-string",
"template": "An example about {yo}"
}
]
}
}
],
"fields": {
"examples": [
{
"yo": "1"
},
{
"yo": "2"
}
],
"exampleTextLengths": [
4,
4
]
}
},
"prefix": "You are a nice assistant",
"examplePrompt": {
"v": 1,
"type": "constructor",
"identifier": [
"langchain",
"prompts",
"prompt",
"PromptTemplate"
],
"arguments": [
{
"inputVariables": [
"yo"
],
"templateFormat": "f-string",
"template": "An example about {yo}"
}
]
},
"suffix": "My name is {name}",
"inputVariables": [
"yo",
"name"
]
}
]
}
}
]
}"
`);
const chain2 = await load<LLMChain>(str);
expect(chain2).toBeInstanceOf(LLMChain);
expect(JSON.stringify(chain2, null, 2)).toBe(str);
});
+21 -4
View File
@@ -6,13 +6,18 @@ import {
PartialValues,
} from "../schema/index.js";
import { BaseOutputParser } from "../schema/output_parser.js";
import { Serializable } from "../schema/load.js";
import { SerializedBasePromptTemplate } from "./serde.js";
export class StringPromptValue extends BasePromptValue {
lc_namespace = ["langchain", "prompts"];
lc_name = "base";
value: string;
constructor(value: string) {
super();
super(...arguments);
this.value = value;
}
@@ -47,9 +52,18 @@ export interface BasePromptTemplateInput {
* Base class for prompt templates. Exposes a format method that returns a
* string prompt given a set of input values.
*/
export abstract class BasePromptTemplate implements BasePromptTemplateInput {
export abstract class BasePromptTemplate
extends Serializable
implements BasePromptTemplateInput
{
declare PromptValueReturnType: BasePromptValue;
lc_namespace = ["langchain", "prompts"];
get lc_name(): string {
return this._getPromptType();
}
inputVariables: string[];
outputParser?: BaseOutputParser;
@@ -57,6 +71,7 @@ export abstract class BasePromptTemplate implements BasePromptTemplateInput {
partialVariables?: InputValues;
constructor(input: BasePromptTemplateInput) {
super(input);
const { inputVariables } = input;
if (inputVariables.includes("stop")) {
throw new Error(
@@ -151,7 +166,7 @@ export abstract class BasePromptTemplate implements BasePromptTemplateInput {
}
export abstract class BaseStringPromptTemplate extends BasePromptTemplate {
async formatPromptValue(values: InputValues): Promise<BasePromptValue> {
async formatPromptValue(values: InputValues): Promise<StringPromptValue> {
const formattedPrompt = await this.format(values);
return new StringPromptValue(formattedPrompt);
}
@@ -160,7 +175,9 @@ export abstract class BaseStringPromptTemplate extends BasePromptTemplate {
/**
* Base class for example selectors.
*/
export abstract class BaseExampleSelector {
export abstract class BaseExampleSelector extends Serializable {
lc_namespace = ["langchain", "prompts"];
abstract addExample(example: Example): Promise<void | string>;
abstract selectExamples(input_variables: Example): Promise<Example[]>;
+15 -6
View File
@@ -8,6 +8,7 @@ import {
PartialValues,
SystemChatMessage,
} from "../schema/index.js";
import { Serializable } from "../schema/load.js";
import {
BasePromptTemplate,
BasePromptTemplateInput,
@@ -19,7 +20,11 @@ import {
SerializedMessagePromptTemplate,
} from "./serde.js";
export abstract class BaseMessagePromptTemplate {
export abstract class BaseMessagePromptTemplate extends Serializable {
lc_namespace = ["langchain", "prompts"];
lc_name = "chat";
abstract inputVariables: string[];
abstract formatMessages(values: InputValues): Promise<BaseChatMessage[]>;
@@ -33,10 +38,14 @@ export abstract class BaseMessagePromptTemplate {
}
export class ChatPromptValue extends BasePromptValue {
lc_namespace = ["langchain", "prompts"];
lc_name = "chat";
messages: BaseChatMessage[];
constructor(messages: BaseChatMessage[]) {
super();
super(...arguments);
this.messages = messages;
}
@@ -53,7 +62,7 @@ export class MessagesPlaceholder extends BaseMessagePromptTemplate {
variableName: string;
constructor(variableName: string) {
super();
super(...arguments);
this.variableName = variableName;
}
@@ -69,8 +78,8 @@ export class MessagesPlaceholder extends BaseMessagePromptTemplate {
export abstract class BaseMessageStringPromptTemplate extends BaseMessagePromptTemplate {
prompt: BaseStringPromptTemplate;
protected constructor(prompt: BaseStringPromptTemplate) {
super();
protected constructor(prompt: BaseStringPromptTemplate, _role?: string) {
super(...arguments);
this.prompt = prompt;
}
@@ -112,7 +121,7 @@ export class ChatMessagePromptTemplate extends BaseMessageStringPromptTemplate {
}
constructor(prompt: BaseStringPromptTemplate, role: string) {
super(prompt);
super(prompt, role);
this.role = role;
}
@@ -1,5 +1,5 @@
import { Example } from "../../schema/index.js";
import type { BaseExampleSelector } from "../base.js";
import { BaseExampleSelector } from "../base.js";
import { PromptTemplate } from "../prompt.js";
function getLengthBased(text: string): number {
@@ -12,7 +12,11 @@ export interface LengthBasedExampleSelectorInput {
getTextLength?: (text: string) => number;
}
export class LengthBasedExampleSelector implements BaseExampleSelector {
export class LengthBasedExampleSelector extends BaseExampleSelector {
lc_name = "selectors";
lc_fields = ["examples", "exampleTextLengths"];
protected examples: Example[] = [];
examplePrompt!: PromptTemplate;
@@ -24,6 +28,7 @@ export class LengthBasedExampleSelector implements BaseExampleSelector {
exampleTextLengths: number[] = [];
constructor(data: LengthBasedExampleSelectorInput) {
super(data);
this.examplePrompt = data.examplePrompt;
this.maxLength = data.maxLength ?? 2048;
this.getTextLength = data.getTextLength ?? getLengthBased;
@@ -2,7 +2,7 @@ import { Embeddings } from "../../embeddings/base.js";
import { VectorStore } from "../../vectorstores/base.js";
import { Document } from "../../document.js";
import { Example } from "../../schema/index.js";
import type { BaseExampleSelector } from "../base.js";
import { BaseExampleSelector } from "../base.js";
function sortedValues<T>(values: Record<string, T>): T[] {
return Object.keys(values)
@@ -17,7 +17,9 @@ export interface SemanticSimilarityExampleSelectorInput {
inputKeys?: string[];
}
export class SemanticSimilarityExampleSelector implements BaseExampleSelector {
export class SemanticSimilarityExampleSelector extends BaseExampleSelector {
lc_name = "selectors";
vectorStore: VectorStore;
k = 4;
@@ -27,6 +29,7 @@ export class SemanticSimilarityExampleSelector implements BaseExampleSelector {
inputKeys?: string[];
constructor(data: SemanticSimilarityExampleSelectorInput) {
super(data);
this.vectorStore = data.vectorStore;
this.k = data.k ?? 4;
this.exampleKeys = data.exampleKeys;
+2 -1
View File
@@ -1,4 +1,5 @@
import { Document } from "../document.js";
import { Serializable } from "./load.js";
export const RUN_KEY = "__run";
@@ -132,7 +133,7 @@ export interface ChatResult {
/**
* Base PromptValue class. All prompt values should extend this class.
*/
export abstract class BasePromptValue {
export abstract class BasePromptValue extends Serializable {
abstract toString(): string;
abstract toChatMessages(): BaseChatMessage[];
+38
View File
@@ -0,0 +1,38 @@
export interface SerializedFields {
[key: string]: unknown;
}
export interface Serialized {
v: number;
type: "constructor" | "function";
identifier: string[];
arguments: unknown[];
fields?: SerializedFields;
}
export abstract class Serializable {
abstract lc_namespace: string[];
abstract lc_name: string;
lc_arguments: unknown[];
lc_fields?: string[];
constructor(...args: unknown[]) {
this.lc_arguments = args;
}
toJSON(): Serialized {
return {
v: 1,
type: "constructor",
identifier: [...this.lc_namespace, this.lc_name, this.constructor.name],
arguments: this.lc_arguments,
fields: this.lc_fields?.reduce((acc, key) => {
acc[key] = this[key as keyof this];
return acc;
}, {} as SerializedFields),
};
}
}
+6
View File
@@ -17,6 +17,12 @@ export abstract class StructuredTool<
> extends BaseLangChain {
abstract schema: T | z.ZodEffects<T>;
lc_namespace = ["langchain", "tools"];
get lc_name(): string {
throw new Error("Not implemented");
}
constructor(fields?: ToolParams) {
super(fields ?? {});
}
+1
View File
@@ -32,6 +32,7 @@
],
"typedocOptions": {
"entryPoints": [
"src/load/index.ts",
"src/agents/index.ts",
"src/agents/load.ts",
"src/base_language/index.ts",
+1
View File
@@ -1,3 +1,4 @@
export * from "langchain/load";
export * from "langchain/agents";
export * from "langchain/base_language";
export * from "langchain/tools";
+1
View File
@@ -1,3 +1,4 @@
const load = require("langchain/load");
const agents = require("langchain/agents");
const base_language = require("langchain/base_language");
const tools = require("langchain/tools");
+1
View File
@@ -1,3 +1,4 @@
export * from "langchain/load";
export * from "langchain/agents";
export * from "langchain/base_language";
export * from "langchain/tools";
+1
View File
@@ -1,3 +1,4 @@
import * as load from "langchain/load";
import * as agents from "langchain/agents";
import * as base_language from "langchain/base_language";
import * as tools from "langchain/tools";
+1
View File
@@ -1,3 +1,4 @@
import * as load from "langchain/load";
import * as agents from "langchain/agents";
import * as base_language from "langchain/base_language";
import * as tools from "langchain/tools";
+1
View File
@@ -1,3 +1,4 @@
export * from "langchain/load";
export * from "langchain/agents";
export * from "langchain/base_language";
export * from "langchain/tools";
+1
View File
@@ -1,3 +1,4 @@
export * from "langchain/load";
export * from "langchain/agents";
export * from "langchain/base_language";
export * from "langchain/tools";