From c706e8cb863ca845b58a92aed450688bc8e9635f Mon Sep 17 00:00:00 2001 From: Jacob Lee Date: Mon, 11 Sep 2023 06:52:32 -0700 Subject: [PATCH] Adds Bun runtime and export test (#2595) --- docker-compose.yml | 10 +++ docs/snippets/get_started/installation.mdx | 1 + .../scripts/docker-bun-ci-entrypoint.sh | 33 +++++++++ .../test-exports-bun/package.json | 29 ++++++++ .../scripts/combine-dependencies.js | 8 +++ .../test-exports-bun/src/entrypoints.js | 69 +++++++++++++++++++ .../test-exports-bun/src/import.cjs | 51 ++++++++++++++ .../test-exports-bun/src/index.js | 45 ++++++++++++ .../test-exports-bun/src/index.ts | 69 +++++++++++++++++++ .../test-exports-bun/src/require.cjs | 51 ++++++++++++++ .../test-exports-bun/tsconfig.json | 16 +++++ langchain/scripts/create-entrypoints.js | 1 + 12 files changed, 383 insertions(+) create mode 100644 environment_tests/scripts/docker-bun-ci-entrypoint.sh create mode 100644 environment_tests/test-exports-bun/package.json create mode 100644 environment_tests/test-exports-bun/scripts/combine-dependencies.js create mode 100644 environment_tests/test-exports-bun/src/entrypoints.js create mode 100644 environment_tests/test-exports-bun/src/import.cjs create mode 100644 environment_tests/test-exports-bun/src/index.js create mode 100644 environment_tests/test-exports-bun/src/index.ts create mode 100644 environment_tests/test-exports-bun/src/require.cjs create mode 100644 environment_tests/test-exports-bun/tsconfig.json diff --git a/docker-compose.yml b/docker-compose.yml index 4019bb7876e6..da5e46cb64e5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -66,6 +66,14 @@ services: - ./environment_tests/scripts:/scripts - ./langchain:/langchain command: bash /scripts/docker-ci-entrypoint.sh + test-exports-bun: + image: oven/bun + working_dir: /app + volumes: + - ./environment_tests/test-exports-bun:/package + - ./environment_tests/scripts:/scripts + - ./langchain:/langchain-workspace + command: bash /scripts/docker-bun-ci-entrypoint.sh success: image: alpine:3.14 command: echo "Success" @@ -82,3 +90,5 @@ services: condition: service_completed_successfully test-exports-vite: condition: service_completed_successfully + test-exports-bun: + condition: service_completed_successfully diff --git a/docs/snippets/get_started/installation.mdx b/docs/snippets/get_started/installation.mdx index 9062e05faebb..3b21f092b6fc 100644 --- a/docs/snippets/get_started/installation.mdx +++ b/docs/snippets/get_started/installation.mdx @@ -16,6 +16,7 @@ LangChain is written in TypeScript and can be used in: - Supabase Edge Functions - Browser - Deno +- Bun ## Installation diff --git a/environment_tests/scripts/docker-bun-ci-entrypoint.sh b/environment_tests/scripts/docker-bun-ci-entrypoint.sh new file mode 100644 index 000000000000..904bfc088775 --- /dev/null +++ b/environment_tests/scripts/docker-bun-ci-entrypoint.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +set -euxo pipefail + +export CI=true + +# enable extended globbing for omitting build artifacts +shopt -s extglob + +# avoid copying build artifacts from the host +cp -r ../package/!(node_modules|dist|dist-cjs|dist-esm|build|.next|.turbo) . + +mkdir ../langchain +cp -r ../langchain-workspace/!(node_modules|build|.next|.turbo) ../langchain + +# Link the package locally +cd ../langchain +bun link + +# Reinstall deps with bun because bun doesn't install deps of linked deps +bun install --no-save + +cd ../app + +# Replace the workspace dependency with the local copy, and install all others +sed -i 's/"langchain": "workspace:\*"/"langchain": "link:langchain"/g' package.json +bun install --no-save + +# Check the build command completes successfully +bun run build + +# Check the test command completes successfully +bun run test diff --git a/environment_tests/test-exports-bun/package.json b/environment_tests/test-exports-bun/package.json new file mode 100644 index 000000000000..02398207b53d --- /dev/null +++ b/environment_tests/test-exports-bun/package.json @@ -0,0 +1,29 @@ +{ + "name": "test-exports-bun", + "version": "0.0.0", + "private": true, + "description": "Tests for the things exported by the langchain package", + "main": "./index.mjs", + "type": "module", + "scripts": { + "build": "tsc", + "test": "bun run test:esm && bun run test:cjs && bun run test:cjs:import && bun run test:entrypoints && bun run test:ts", + "test:esm": "bun src/index.js", + "test:cjs": "bun src/require.cjs", + "test:cjs:import": "bun src/import.cjs", + "test:entrypoints": "bun src/entrypoints.js", + "test:ts": "bun dist/index.js" + }, + "author": "LangChain", + "license": "MIT", + "dependencies": { + "d3-dsv": "2", + "hnswlib-node": "^1.4.2", + "langchain": "workspace:*" + }, + "devDependencies": { + "@tsconfig/recommended": "^1.0.2", + "@types/node": "^18.15.11", + "typescript": "^5.0.0" + } +} diff --git a/environment_tests/test-exports-bun/scripts/combine-dependencies.js b/environment_tests/test-exports-bun/scripts/combine-dependencies.js new file mode 100644 index 000000000000..74ffbb2b9514 --- /dev/null +++ b/environment_tests/test-exports-bun/scripts/combine-dependencies.js @@ -0,0 +1,8 @@ +import * as fs from "fs"; + +const langchainPackageJson = JSON.parse(fs.readFileSync("../langchain/package.json")); +const testPackageJson = JSON.parse(fs.readFileSync("./package.json")); + +testPackageJson.dependencies = { ...testPackageJson.dependencies, ...langchainPackageJson.dependencies }; + +fs.writeFileSync("./package.json", JSON.stringify(testPackageJson, null, 2)); \ No newline at end of file diff --git a/environment_tests/test-exports-bun/src/entrypoints.js b/environment_tests/test-exports-bun/src/entrypoints.js new file mode 100644 index 000000000000..0cef0f43a27f --- /dev/null +++ b/environment_tests/test-exports-bun/src/entrypoints.js @@ -0,0 +1,69 @@ +export * from "langchain/load"; +export * from "langchain/load/serializable"; +export * from "langchain/agents"; +export * from "langchain/agents/toolkits"; +export * from "langchain/base_language"; +export * from "langchain/tools"; +export * from "langchain/chains"; +export * from "langchain/chains/openai_functions"; +export * from "langchain/embeddings/base"; +export * from "langchain/embeddings/cache_backed"; +export * from "langchain/embeddings/fake"; +export * from "langchain/embeddings/ollama"; +export * from "langchain/embeddings/openai"; +export * from "langchain/embeddings/minimax"; +export * from "langchain/llms/base"; +export * from "langchain/llms/openai"; +export * from "langchain/llms/ai21"; +export * from "langchain/llms/aleph_alpha"; +export * from "langchain/llms/ollama"; +export * from "langchain/prompts"; +export * from "langchain/vectorstores/base"; +export * from "langchain/vectorstores/memory"; +export * from "langchain/vectorstores/prisma"; +export * from "langchain/vectorstores/vectara"; +export * from "langchain/vectorstores/xata"; +export * from "langchain/text_splitter"; +export * from "langchain/memory"; +export * from "langchain/document"; +export * from "langchain/document_loaders/base"; +export * from "langchain/document_loaders/web/serpapi"; +export * from "langchain/document_loaders/web/sort_xyz_blockchain"; +export * from "langchain/document_transformers/openai_functions"; +export * from "langchain/chat_models/base"; +export * from "langchain/chat_models/openai"; +export * from "langchain/chat_models/anthropic"; +export * from "langchain/chat_models/baiduwenxin"; +export * from "langchain/chat_models/ollama"; +export * from "langchain/chat_models/minimax"; +export * from "langchain/schema"; +export * from "langchain/schema/document"; +export * from "langchain/schema/output_parser"; +export * from "langchain/schema/query_constructor"; +export * from "langchain/schema/retriever"; +export * from "langchain/schema/runnable"; +export * from "langchain/schema/storage"; +export * from "langchain/callbacks"; +export * from "langchain/output_parsers"; +export * from "langchain/retrievers/remote"; +export * from "langchain/retrievers/databerry"; +export * from "langchain/retrievers/contextual_compression"; +export * from "langchain/retrievers/document_compressors"; +export * from "langchain/retrievers/multi_vector"; +export * from "langchain/retrievers/parent_document"; +export * from "langchain/retrievers/time_weighted"; +export * from "langchain/retrievers/document_compressors/chain_extract"; +export * from "langchain/retrievers/hyde"; +export * from "langchain/retrievers/score_threshold"; +export * from "langchain/retrievers/vespa"; +export * from "langchain/cache"; +export * from "langchain/stores/doc/in_memory"; +export * from "langchain/stores/file/in_memory"; +export * from "langchain/stores/message/in_memory"; +export * from "langchain/storage/in_memory"; +export * from "langchain/util/math"; +export * from "langchain/experimental/autogpt"; +export * from "langchain/experimental/babyagi"; +export * from "langchain/experimental/generative_agents"; +export * from "langchain/experimental/plan_and_execute"; +export * from "langchain/evaluation"; diff --git a/environment_tests/test-exports-bun/src/import.cjs b/environment_tests/test-exports-bun/src/import.cjs new file mode 100644 index 000000000000..2501ddc98205 --- /dev/null +++ b/environment_tests/test-exports-bun/src/import.cjs @@ -0,0 +1,51 @@ +async function test() { + const { default: assert } = await import("assert"); + const { OpenAI } = await import("langchain/llms/openai"); + const { LLMChain } = await import("langchain/chains"); + const { ChatPromptTemplate } = await import("langchain/prompts"); + const { loadPrompt } = await import("langchain/prompts/load"); + const { MemoryVectorStore } = await import("langchain/vectorstores/memory"); + const { OpenAIEmbeddings } = await import("langchain/embeddings/openai"); + const { Document } = await import("langchain/document"); + const { CSVLoader } = await import("langchain/document_loaders/fs/csv"); + + // Test exports + assert(typeof OpenAI === "function"); + assert(typeof LLMChain === "function"); + assert(typeof loadPrompt === "function"); + assert(typeof ChatPromptTemplate === "function"); + assert(typeof MemoryVectorStore === "function"); + + const vs = new MemoryVectorStore(new OpenAIEmbeddings({ openAIApiKey: "sk-XXXX" })); + + await vs.addVectors( + [ + [0, 1, 0], + [0, 0, 1], + ], + [ + new Document({ + pageContent: "a", + }), + new Document({ + pageContent: "b", + }), + ] + ); + + assert((await vs.similaritySearchVectorWithScore([0, 0, 1], 1)).length === 1); + + // Test CSVLoader + const loader = new CSVLoader(new Blob(["a,b,c\n1,2,3\n4,5,6"])); + + const docs = await loader.load(); + + assert(docs.length === 2); +} + +test() + .then(() => console.log("success")) + .catch((e) => { + console.error(e); + process.exit(1); + }); diff --git a/environment_tests/test-exports-bun/src/index.js b/environment_tests/test-exports-bun/src/index.js new file mode 100644 index 000000000000..043663c5cc29 --- /dev/null +++ b/environment_tests/test-exports-bun/src/index.js @@ -0,0 +1,45 @@ +import assert from "assert"; +import { OpenAI } from "langchain/llms/openai"; +import { LLMChain } from "langchain/chains"; +import { ChatPromptTemplate } from "langchain/prompts"; +import { loadPrompt } from "langchain/prompts/load"; +import { MemoryVectorStore } from "langchain/vectorstores/memory"; +import { OpenAIEmbeddings } from "langchain/embeddings/openai"; +import { Document } from "langchain/document"; +import { CSVLoader } from "langchain/document_loaders/fs/csv"; +import { CallbackManager } from "langchain/callbacks"; + +// Test exports +assert(typeof OpenAI === "function"); +assert(typeof LLMChain === "function"); +assert(typeof loadPrompt === "function"); +assert(typeof ChatPromptTemplate === "function"); +assert(typeof MemoryVectorStore === "function"); +assert(typeof OpenAIEmbeddings === "function"); +assert(typeof CallbackManager === "function"); + +const vs = new MemoryVectorStore(new OpenAIEmbeddings({ openAIApiKey: "sk-XXXX" })); + +await vs.addVectors( + [ + [0, 1, 0], + [0, 0, 1], + ], + [ + new Document({ + pageContent: "a", + }), + new Document({ + pageContent: "b", + }), + ] +); + +assert((await vs.similaritySearchVectorWithScore([0, 0, 1], 1)).length === 1); + +// Test CSVLoader +const loader = new CSVLoader(new Blob(["a,b,c\n1,2,3\n4,5,6"])); + +const docs = await loader.load(); + +assert(docs.length === 2); diff --git a/environment_tests/test-exports-bun/src/index.ts b/environment_tests/test-exports-bun/src/index.ts new file mode 100644 index 000000000000..9134e025ca22 --- /dev/null +++ b/environment_tests/test-exports-bun/src/index.ts @@ -0,0 +1,69 @@ +import assert from "assert"; +import { OpenAI } from "langchain/llms/openai"; +import { LLMChain } from "langchain/chains"; +import { ChatPromptTemplate } from "langchain/prompts"; +import { loadPrompt } from "langchain/prompts/load"; +import { MemoryVectorStore } from "langchain/vectorstores/memory"; +import { OpenAIEmbeddings } from "langchain/embeddings/openai"; +import { Document } from "langchain/document"; +import { CSVLoader } from "langchain/document_loaders/fs/csv"; + +async function test(useAzure: boolean = false) { + // Test exports + assert(typeof OpenAI === "function"); + assert(typeof LLMChain === "function"); + assert(typeof loadPrompt === "function"); + assert(typeof ChatPromptTemplate === "function"); + assert(typeof MemoryVectorStore === "function"); + + // Test dynamic imports of peer dependencies + const openAIParameters = useAzure + ? { + azureOpenAIApiKey: "sk-XXXX", + azureOpenAIApiInstanceName: "XXXX", + azureOpenAIApiDeploymentName: "XXXX", + azureOpenAIApiVersion: "XXXX", + } + : { + openAIApiKey: "sk-XXXX", + }; + + const vs = new MemoryVectorStore(new OpenAIEmbeddings(openAIParameters)); + + await vs.addVectors( + [ + [0, 1, 0], + [0, 0, 1], + ], + [ + new Document({ + pageContent: "a", + }), + new Document({ + pageContent: "b", + }), + ] + ); + + assert((await vs.similaritySearchVectorWithScore([0, 0, 1], 1)).length === 1); + + // Test CSVLoader + const loader = new CSVLoader(new Blob(["a,b,c\n1,2,3\n4,5,6"])); + + const docs = await loader.load(); + + assert(docs.length === 2); +} + +test(false) + .then(() => console.log("openAI Api success")) + .catch((e) => { + console.error(e); + process.exit(1); + }); +test(true) + .then(() => console.log("Azure openAI Api success")) + .catch((e) => { + console.error(e); + process.exit(1); + }); diff --git a/environment_tests/test-exports-bun/src/require.cjs b/environment_tests/test-exports-bun/src/require.cjs new file mode 100644 index 000000000000..e6f9ac37b8d8 --- /dev/null +++ b/environment_tests/test-exports-bun/src/require.cjs @@ -0,0 +1,51 @@ +const assert = require("assert"); +const { OpenAI } = require("langchain/llms/openai"); +const { LLMChain } = require("langchain/chains"); +const { ChatPromptTemplate } = require("langchain/prompts"); +const { loadPrompt } = require("langchain/prompts/load"); +const { MemoryVectorStore } = require("langchain/vectorstores/memory"); +const { OpenAIEmbeddings } = require("langchain/embeddings/openai"); +const { Document } = require("langchain/document"); +const { CSVLoader } = require("langchain/document_loaders/fs/csv"); + +async function test() { + // Test exports + assert(typeof OpenAI === "function"); + assert(typeof LLMChain === "function"); + assert(typeof loadPrompt === "function"); + assert(typeof ChatPromptTemplate === "function"); + assert(typeof MemoryVectorStore === "function"); + + const vs = new MemoryVectorStore(new OpenAIEmbeddings({ openAIApiKey: "sk-XXXX" })); + + await vs.addVectors( + [ + [0, 1, 0], + [0, 0, 1], + ], + [ + new Document({ + pageContent: "a", + }), + new Document({ + pageContent: "b", + }), + ] + ); + + assert((await vs.similaritySearchVectorWithScore([0, 0, 1], 1)).length === 1); + + // Test CSVLoader + const loader = new CSVLoader(new Blob(["a,b,c\n1,2,3\n4,5,6"])); + + const docs = await loader.load(); + + assert(docs.length === 2); +} + +test() + .then(() => console.log("success")) + .catch((e) => { + console.error(e); + process.exit(1); + }); diff --git a/environment_tests/test-exports-bun/tsconfig.json b/environment_tests/test-exports-bun/tsconfig.json new file mode 100644 index 000000000000..37f4ef4fb079 --- /dev/null +++ b/environment_tests/test-exports-bun/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "@tsconfig/recommended", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "lib": [ + "ES2021", + "ES2022.Object", + "DOM" + ], + "target": "ES2021", + }, + "include": [ + "src/**/*" + ] +} diff --git a/langchain/scripts/create-entrypoints.js b/langchain/scripts/create-entrypoints.js index b834c83b8f62..5fd6750d8e75 100644 --- a/langchain/scripts/create-entrypoints.js +++ b/langchain/scripts/create-entrypoints.js @@ -397,6 +397,7 @@ const testExports = [ ["test-exports-cf", (p) => `export * from "langchain/${p}";`], ["test-exports-vercel", (p) => `export * from "langchain/${p}";`], ["test-exports-vite", (p) => `export * from "langchain/${p}";`], + ["test-exports-bun", (p) => `export * from "langchain/${p}";`], ]; const updateJsonFile = (relativePath, updateFunction) => {