diff --git a/docker-compose.yml b/docker-compose.yml
index f050399fc8a9..d07b5cfb3a1b 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -11,6 +11,7 @@ services:
- ./environment_tests/scripts:/scripts
- ./langchain:/langchain
- ./langchain-core:/langchain-core
+ - ./libs/langchain-community:/langchain-community
- ./libs/langchain-anthropic:/langchain-anthropic
- ./libs/langchain-openai:/langchain-openai
command: bash /scripts/docker-ci-entrypoint.sh
@@ -25,6 +26,7 @@ services:
- ./environment_tests/scripts:/scripts
- ./langchain:/langchain
- ./langchain-core:/langchain-core
+ - ./libs/langchain-community:/langchain-community
- ./libs/langchain-anthropic:/langchain-anthropic
- ./libs/langchain-openai:/langchain-openai
command: bash /scripts/docker-ci-entrypoint.sh
@@ -39,6 +41,7 @@ services:
- ./environment_tests/scripts:/scripts
- ./langchain:/langchain
- ./langchain-core:/langchain-core
+ - ./libs/langchain-community:/langchain-community
- ./libs/langchain-anthropic:/langchain-anthropic
- ./libs/langchain-openai:/langchain-openai
command: bash /scripts/docker-ci-entrypoint.sh
@@ -53,6 +56,7 @@ services:
- ./environment_tests/scripts:/scripts
- ./langchain:/langchain
- ./langchain-core:/langchain-core
+ - ./libs/langchain-community:/langchain-community
- ./libs/langchain-anthropic:/langchain-anthropic
- ./libs/langchain-openai:/langchain-openai
command: bash /scripts/docker-ci-entrypoint.sh
@@ -67,6 +71,7 @@ services:
- ./environment_tests/scripts:/scripts
- ./langchain:/langchain
- ./langchain-core:/langchain-core
+ - ./libs/langchain-community:/langchain-community
- ./libs/langchain-anthropic:/langchain-anthropic
- ./libs/langchain-openai:/langchain-openai
command: bash /scripts/docker-ci-entrypoint.sh
@@ -81,6 +86,7 @@ services:
- ./environment_tests/scripts:/scripts
- ./langchain:/langchain
- ./langchain-core:/langchain-core
+ - ./libs/langchain-community:/langchain-community
- ./libs/langchain-anthropic:/langchain-anthropic
- ./libs/langchain-openai:/langchain-openai
command: bash /scripts/docker-ci-entrypoint.sh
@@ -92,6 +98,7 @@ services:
# - ./environment_tests/scripts:/scripts
# - ./langchain:/langchain-workspace
# - ./langchain-core:/langchain-core
+ # - ./libs/langchain-community:/langchain-community-workspace
# - ./libs/langchain-anthropic:/langchain-anthropic-workspace
# command: bash /scripts/docker-bun-ci-entrypoint.sh
success:
diff --git a/docs/core_docs/docs/expression_language/get_started.mdx b/docs/core_docs/docs/expression_language/get_started.mdx
new file mode 100644
index 000000000000..a3e6e8035675
--- /dev/null
+++ b/docs/core_docs/docs/expression_language/get_started.mdx
@@ -0,0 +1,92 @@
+---
+sidebar_position: 0
+title: Get started
+---
+
+import CodeBlock from "@theme/CodeBlock";
+import BasicExample from "@examples/guides/expression_language/get_started/basic.ts";
+import BasicPromptExample from "@examples/guides/expression_language/get_started/prompt.ts";
+import BasicChatModelExample from "@examples/guides/expression_language/get_started/chat_model.ts";
+import BasicLLMModelExample from "@examples/guides/expression_language/get_started/llm_model.ts";
+import BasicOutputParserExample from "@examples/guides/expression_language/get_started/output_parser.ts";
+import BasicRagExample from "@examples/guides/expression_language/get_started/rag.ts";
+
+# Get started
+
+LCEL makes it easy to build complex chains from basic components, and supports out of the box functionality such as streaming, parallelism, and logging.
+
+## Basic example: prompt + model + output parser
+
+The most basic and common use case is chaining a prompt template and a model together. To see how this works, let's create a chain that takes a topic and generates a joke:
+
+{BasicExample}
+
+:::tip
+
+[LangSmith trace](https://smith.langchain.com/public/dcac6d79-5254-4889-a974-4b3abaf605b4/r)
+
+:::
+
+Notice in this line we're chaining our prompt, LLM model and output parser together:
+
+```typescript
+const chain = prompt.pipe(model).pipe(outputParser);
+```
+
+The `.pipe()` method allows for chaining together any number of runnables. It will pass the output of one through to the input of the next.
+
+Here, the prompt is passed a `topic` and when invoked it returns a formatted string with the `{topic}` input variable replaced with the string we passed to the invoke call.
+That string is then passed as the input to the LLM which returns a `BaseMessage` object. Finally, the output parser takes that `BaseMessage` object and returns the content of that object as a string.
+
+### 1. Prompt
+
+`prompt` is a `BasePromptTemplate`, which means it takes in an object of template variables and produces a `PromptValue`.
+A `PromptValue` is a wrapper around a completed prompt that can be passed to either an `LLM` (which takes a string as input) or `ChatModel` (which takes a sequence of messages as input).
+It can work with either language model type because it defines logic both for producing BaseMessages and for producing a string.
+
+{BasicPromptExample}
+
+### 2. Model
+
+The `PromptValue` is then passed to `model`. In this case our `model` is a `ChatModel`, meaning it will output a `BaseMessage`.
+
+{BasicChatModelExample}
+
+If our model was an LLM, it would output a string.
+
+{BasicLLMModelExample}
+
+### 3. Output parser
+
+And lastly we pass our `model` output to the `outputParser`, which is a `BaseOutputParser` meaning it takes either a string or a `BaseMessage` as input. The `StringOutputParser` specifically simple converts any input into a string.
+
+{BasicOutputParserExample}
+
+## RAG Search Example
+
+For our next example, we want to run a retrieval-augmented generation chain to add some context when responding to questions.
+
+{BasicRagExample}
+
+:::tip
+
+[LangSmith trace](https://smith.langchain.com/public/f0205e20-c46f-47cd-a3a4-6a95451f8a25/r)
+
+:::
+
+In this chain we add some extra logic around retrieving context from a vector store.
+
+We first instantiated our model, vector store and output parser. Then we defined our prompt, which takes in two input variables:
+
+- `context` -> this is a string which is returned from our vector store based on a semantic search from the input.
+- `question` -> this is the question we want to ask.
+
+Next we created a `setupAndRetriever` runnable. This has two components which return the values required by our prompt:
+
+- `context` -> this is a `RunnableLambda` which takes the input from the `.invoke()` call, makes a request to our vector store, and returns the first result.
+- `question` -> this uses a `RunnablePassthrough` which simply passes whatever the input was through to the next step, and in our case it returns it to the key in the object we defined.
+
+Both of these are wrapped inside a `RunnableMap`. This is a special type of runnable that takes an object of runnables and executes them all in parallel.
+It then returns an object with the same keys as the input object, but with the values replaced with the output of the runnables.
+
+Finally, we pass the output of the `setupAndRetriever` to our `prompt` and then to our `model` and `outputParser` as before.
diff --git a/environment_tests/scripts/docker-ci-entrypoint.sh b/environment_tests/scripts/docker-ci-entrypoint.sh
index dd98d4276256..a4e2d45e7d45 100644
--- a/environment_tests/scripts/docker-ci-entrypoint.sh
+++ b/environment_tests/scripts/docker-ci-entrypoint.sh
@@ -19,6 +19,7 @@ cp ../root/yarn.lock ../root/.yarnrc.yml .
# Avoid calling "yarn add ../langchain" as yarn berry does seem to hang for ~30s
# before installation actually occurs
sed -i 's/"@langchain\/core": "workspace:\*"/"@langchain\/core": "..\/langchain-core"/g' package.json
+sed -i 's/"@langchain\/community": "workspace:\*"/"@langchain\/community": "..\/langchain-community"/g' package.json
sed -i 's/"@langchain\/anthropic": "workspace:\*"/"@langchain\/anthropic": "..\/langchain-anthropic"/g' package.json
sed -i 's/"@langchain\/openai": "workspace:\*"/"@langchain\/openai": "..\/langchain-openai"/g' package.json
sed -i 's/"langchain": "workspace:\*"/"langchain": "..\/langchain"/g' package.json
diff --git a/environment_tests/test-exports-bun/package.json b/environment_tests/test-exports-bun/package.json
index 8294ac754257..649c5e7a1f3d 100644
--- a/environment_tests/test-exports-bun/package.json
+++ b/environment_tests/test-exports-bun/package.json
@@ -18,6 +18,7 @@
"license": "MIT",
"dependencies": {
"@langchain/anthropic": "workspace:*",
+ "@langchain/community": "workspace:*",
"@langchain/core": "workspace:*",
"@langchain/openai": "workspace:*",
"d3-dsv": "2",
diff --git a/environment_tests/test-exports-cf/package.json b/environment_tests/test-exports-cf/package.json
index b87c55713fda..fa01eb216974 100644
--- a/environment_tests/test-exports-cf/package.json
+++ b/environment_tests/test-exports-cf/package.json
@@ -9,6 +9,7 @@
},
"dependencies": {
"@langchain/anthropic": "workspace:*",
+ "@langchain/community": "workspace:*",
"@langchain/core": "workspace:*",
"@langchain/openai": "workspace:*",
"langchain": "workspace:*"
diff --git a/environment_tests/test-exports-cjs/package.json b/environment_tests/test-exports-cjs/package.json
index b0b43151e2b4..e9aecb14e38d 100644
--- a/environment_tests/test-exports-cjs/package.json
+++ b/environment_tests/test-exports-cjs/package.json
@@ -19,6 +19,7 @@
"license": "MIT",
"dependencies": {
"@langchain/anthropic": "workspace:*",
+ "@langchain/community": "workspace:*",
"@langchain/core": "workspace:*",
"@langchain/openai": "workspace:*",
"d3-dsv": "2",
diff --git a/environment_tests/test-exports-esbuild/package.json b/environment_tests/test-exports-esbuild/package.json
index 15241cd5ef20..5d456fba7335 100644
--- a/environment_tests/test-exports-esbuild/package.json
+++ b/environment_tests/test-exports-esbuild/package.json
@@ -17,6 +17,7 @@
"license": "MIT",
"dependencies": {
"@langchain/anthropic": "workspace:*",
+ "@langchain/community": "workspace:*",
"@langchain/core": "workspace:*",
"@langchain/openai": "workspace:*",
"d3-dsv": "2",
diff --git a/environment_tests/test-exports-esm/package.json b/environment_tests/test-exports-esm/package.json
index a79fc8e8b174..9eeb68a80474 100644
--- a/environment_tests/test-exports-esm/package.json
+++ b/environment_tests/test-exports-esm/package.json
@@ -20,6 +20,7 @@
"license": "MIT",
"dependencies": {
"@langchain/anthropic": "workspace:*",
+ "@langchain/community": "workspace:*",
"@langchain/core": "workspace:*",
"@langchain/openai": "workspace:*",
"d3-dsv": "2",
diff --git a/environment_tests/test-exports-vercel/package.json b/environment_tests/test-exports-vercel/package.json
index c784c3d21a8d..dde8eb4e7128 100644
--- a/environment_tests/test-exports-vercel/package.json
+++ b/environment_tests/test-exports-vercel/package.json
@@ -10,6 +10,7 @@
},
"dependencies": {
"@langchain/anthropic": "workspace:*",
+ "@langchain/community": "workspace:*",
"@langchain/core": "workspace:*",
"@langchain/openai": "workspace:*",
"@types/node": "18.15.11",
diff --git a/environment_tests/test-exports-vite/package.json b/environment_tests/test-exports-vite/package.json
index 3a3ea14886d5..2240bd9398ca 100644
--- a/environment_tests/test-exports-vite/package.json
+++ b/environment_tests/test-exports-vite/package.json
@@ -11,6 +11,7 @@
},
"dependencies": {
"@langchain/anthropic": "workspace:*",
+ "@langchain/community": "workspace:*",
"@langchain/core": "workspace:*",
"@langchain/openai": "workspace:*",
"langchain": "workspace:*"
diff --git a/examples/src/experimental/masking/basic.ts b/examples/src/experimental/masking/basic.ts
index 77a5c78de2b2..7d364ab00449 100644
--- a/examples/src/experimental/masking/basic.ts
+++ b/examples/src/experimental/masking/basic.ts
@@ -20,11 +20,11 @@ maskingParser.addTransformer(piiMaskingTransformer);
const input =
"Contact me at jane.doe@email.com or 555-123-4567. Also reach me at john.smith@email.com";
-const masked = await maskingParser.parse(input);
+const masked = await maskingParser.mask(input);
console.log(masked);
// Contact me at [email-a31e486e324f6] or [phone-da8fc1584f224]. Also reach me at [email-d5b6237633d95]
-const rehydrated = maskingParser.rehydrate(masked);
+const rehydrated = await maskingParser.rehydrate(masked);
console.log(rehydrated);
// Contact me at jane.doe@email.com or 555-123-4567. Also reach me at john.smith@email.com
diff --git a/examples/src/experimental/masking/kitchen_sink.ts b/examples/src/experimental/masking/kitchen_sink.ts
index 07e85e7fc50f..4743c20a7b2f 100644
--- a/examples/src/experimental/masking/kitchen_sink.ts
+++ b/examples/src/experimental/masking/kitchen_sink.ts
@@ -70,7 +70,7 @@ const message =
// Mask and rehydrate the message
maskingParser
- .parse(message)
+ .mask(message)
.then((maskedMessage: string) => {
console.log(`Masked message: ${maskedMessage}`);
return maskingParser.rehydrate(maskedMessage);
diff --git a/examples/src/experimental/masking/next.ts b/examples/src/experimental/masking/next.ts
index 85621a4b8dca..dac49a781978 100644
--- a/examples/src/experimental/masking/next.ts
+++ b/examples/src/experimental/masking/next.ts
@@ -36,11 +36,11 @@ export async function POST(req: Request) {
const formattedPreviousMessages = messages.slice(0, -1).map(formatMessage);
const currentMessageContent = messages[messages.length - 1].content; // Extract the content of the last message
// Mask sensitive information in the current message
- const guardedMessageContent = await maskingParser.parse(
+ const guardedMessageContent = await maskingParser.mask(
currentMessageContent
);
// Mask sensitive information in the chat history
- const guardedHistory = await maskingParser.parse(
+ const guardedHistory = await maskingParser.mask(
formattedPreviousMessages.join("\n")
);
@@ -64,6 +64,11 @@ export async function POST(req: Request) {
headers: { "content-type": "text/plain; charset=utf-8" },
});
} catch (e: any) {
- return Response.json({ error: e.message }, { status: 500 });
+ return new Response(JSON.stringify({ error: e.message }), {
+ status: 500,
+ headers: {
+ "content-type": "application/json",
+ },
+ });
}
}
diff --git a/examples/src/guides/expression_language/get_started/basic.ts b/examples/src/guides/expression_language/get_started/basic.ts
new file mode 100644
index 000000000000..a6035b82a531
--- /dev/null
+++ b/examples/src/guides/expression_language/get_started/basic.ts
@@ -0,0 +1,20 @@
+import { ChatOpenAI } from "langchain/chat_models/openai";
+import { ChatPromptTemplate } from "langchain/prompts";
+import { StringOutputParser } from "langchain/schema/output_parser";
+
+const prompt = ChatPromptTemplate.fromMessages([
+ ["human", "Tell me a short joke about {topic}"],
+]);
+const model = new ChatOpenAI({});
+const outputParser = new StringOutputParser();
+
+const chain = prompt.pipe(model).pipe(outputParser);
+
+const response = await chain.invoke({
+ topic: "ice cream",
+});
+console.log(response);
+/**
+Why did the ice cream go to the gym?
+Because it wanted to get a little "cone"ditioning!
+ */
diff --git a/examples/src/guides/expression_language/get_started/chat_model.ts b/examples/src/guides/expression_language/get_started/chat_model.ts
new file mode 100644
index 000000000000..f1da2c7c8072
--- /dev/null
+++ b/examples/src/guides/expression_language/get_started/chat_model.ts
@@ -0,0 +1,14 @@
+import { ChatOpenAI } from "langchain/chat_models/openai";
+
+const model = new ChatOpenAI({});
+const promptAsString = "Human: Tell me a short joke about ice cream";
+
+const response = await model.invoke(promptAsString);
+console.log(response);
+/**
+AIMessage {
+ content: 'Sure, here you go: Why did the ice cream go to school? Because it wanted to get a little "sundae" education!',
+ name: undefined,
+ additional_kwargs: { function_call: undefined, tool_calls: undefined }
+}
+ */
diff --git a/examples/src/guides/expression_language/get_started/llm_model.ts b/examples/src/guides/expression_language/get_started/llm_model.ts
new file mode 100644
index 000000000000..e689a8f828a0
--- /dev/null
+++ b/examples/src/guides/expression_language/get_started/llm_model.ts
@@ -0,0 +1,12 @@
+import { OpenAI } from "langchain/llms/openai";
+
+const model = new OpenAI({});
+const promptAsString = "Human: Tell me a short joke about ice cream";
+
+const response = await model.invoke(promptAsString);
+console.log(response);
+/**
+Why did the ice cream go to therapy?
+
+Because it was feeling a little rocky road.
+ */
diff --git a/examples/src/guides/expression_language/get_started/output_parser.ts b/examples/src/guides/expression_language/get_started/output_parser.ts
new file mode 100644
index 000000000000..7640166c1452
--- /dev/null
+++ b/examples/src/guides/expression_language/get_started/output_parser.ts
@@ -0,0 +1,12 @@
+import { AIMessage } from "langchain/schema";
+import { StringOutputParser } from "langchain/schema/output_parser";
+
+const outputParser = new StringOutputParser();
+const message = new AIMessage(
+ 'Sure, here you go: Why did the ice cream go to school? Because it wanted to get a little "sundae" education!'
+);
+const parsed = await outputParser.invoke(message);
+console.log(parsed);
+/**
+Sure, here you go: Why did the ice cream go to school? Because it wanted to get a little "sundae" education!
+ */
diff --git a/examples/src/guides/expression_language/get_started/prompt.ts b/examples/src/guides/expression_language/get_started/prompt.ts
new file mode 100644
index 000000000000..fe178719f954
--- /dev/null
+++ b/examples/src/guides/expression_language/get_started/prompt.ts
@@ -0,0 +1,34 @@
+import { ChatPromptTemplate } from "langchain/prompts";
+
+const prompt = ChatPromptTemplate.fromMessages([
+ ["human", "Tell me a short joke about {topic}"],
+]);
+const promptValue = await prompt.invoke({ topic: "ice cream" });
+console.log(promptValue);
+/**
+ChatPromptValue {
+ messages: [
+ HumanMessage {
+ content: 'Tell me a short joke about ice cream',
+ name: undefined,
+ additional_kwargs: {}
+ }
+ ]
+}
+ */
+const promptAsMessages = promptValue.toChatMessages();
+console.log(promptAsMessages);
+/**
+[
+ HumanMessage {
+ content: 'Tell me a short joke about ice cream',
+ name: undefined,
+ additional_kwargs: {}
+ }
+]
+ */
+const promptAsString = promptValue.toString();
+console.log(promptAsString);
+/**
+Human: Tell me a short joke about ice cream
+ */
diff --git a/examples/src/guides/expression_language/get_started/rag.ts b/examples/src/guides/expression_language/get_started/rag.ts
new file mode 100644
index 000000000000..5127c837ff93
--- /dev/null
+++ b/examples/src/guides/expression_language/get_started/rag.ts
@@ -0,0 +1,47 @@
+import { ChatOpenAI } from "langchain/chat_models/openai";
+import { Document } from "langchain/document";
+import { OpenAIEmbeddings } from "langchain/embeddings/openai";
+import { ChatPromptTemplate } from "langchain/prompts";
+import {
+ RunnableLambda,
+ RunnableMap,
+ RunnablePassthrough,
+} from "langchain/runnables";
+import { StringOutputParser } from "langchain/schema/output_parser";
+import { HNSWLib } from "langchain/vectorstores/hnswlib";
+
+const vectorStore = await HNSWLib.fromDocuments(
+ [
+ new Document({ pageContent: "Harrison worked at Kensho" }),
+ new Document({ pageContent: "Bears like to eat honey." }),
+ ],
+ new OpenAIEmbeddings()
+);
+const retriever = vectorStore.asRetriever(1);
+
+const prompt = ChatPromptTemplate.fromMessages([
+ [
+ "ai",
+ `Answer the question based on only the following context:
+
+{context}`,
+ ],
+ ["human", "{question}"],
+]);
+const model = new ChatOpenAI({});
+const outputParser = new StringOutputParser();
+
+const setupAndRetrieval = RunnableMap.from({
+ context: new RunnableLambda({
+ func: (input: string) =>
+ retriever.invoke(input).then((response) => response[0].pageContent),
+ }).withConfig({ runName: "contextRetriever" }),
+ question: new RunnablePassthrough(),
+});
+const chain = setupAndRetrieval.pipe(prompt).pipe(model).pipe(outputParser);
+
+const response = await chain.invoke("Where did Harrison work?");
+console.log(response);
+/**
+Harrison worked at Kensho.
+ */
diff --git a/langchain-core/.gitignore b/langchain-core/.gitignore
index 05ba9919a328..c6100ae28393 100644
--- a/langchain-core/.gitignore
+++ b/langchain-core/.gitignore
@@ -106,6 +106,9 @@ utils/json_patch.d.ts
utils/json_schema.cjs
utils/json_schema.js
utils/json_schema.d.ts
+utils/math.cjs
+utils/math.js
+utils/math.d.ts
utils/stream.cjs
utils/stream.js
utils/stream.d.ts
diff --git a/langchain-core/package.json b/langchain-core/package.json
index 132e1840c301..fafa426e1b89 100644
--- a/langchain-core/package.json
+++ b/langchain-core/package.json
@@ -1,6 +1,6 @@
{
"name": "@langchain/core",
- "version": "0.0.10",
+ "version": "0.0.11-rc.1",
"description": "Core LangChain.js abstractions and schemas",
"type": "module",
"engines": {
@@ -40,6 +40,7 @@
"decamelize": "1.2.0",
"js-tiktoken": "^1.0.8",
"langsmith": "~0.0.48",
+ "ml-distance": "^4.0.0",
"p-queue": "^6.6.2",
"p-retry": "4",
"uuid": "^9.0.0",
@@ -59,6 +60,7 @@
"eslint-plugin-prettier": "^4.2.1",
"jest": "^29.5.0",
"jest-environment-node": "^29.6.4",
+ "ml-matrix": "^6.10.4",
"prettier": "^2.8.3",
"release-it": "^15.10.1",
"rimraf": "^5.0.1",
@@ -263,6 +265,11 @@
"import": "./utils/json_schema.js",
"require": "./utils/json_schema.cjs"
},
+ "./utils/math": {
+ "types": "./utils/math.d.ts",
+ "import": "./utils/math.js",
+ "require": "./utils/math.cjs"
+ },
"./utils/stream": {
"types": "./utils/stream.d.ts",
"import": "./utils/stream.js",
@@ -400,6 +407,9 @@
"utils/json_schema.cjs",
"utils/json_schema.js",
"utils/json_schema.d.ts",
+ "utils/math.cjs",
+ "utils/math.js",
+ "utils/math.d.ts",
"utils/stream.cjs",
"utils/stream.js",
"utils/stream.d.ts",
diff --git a/langchain-core/scripts/create-entrypoints.js b/langchain-core/scripts/create-entrypoints.js
index b49de2176afb..328796a52d64 100644
--- a/langchain-core/scripts/create-entrypoints.js
+++ b/langchain-core/scripts/create-entrypoints.js
@@ -44,6 +44,7 @@ const entrypoints = {
"utils/hash": "utils/hash",
"utils/json_patch": "utils/json_patch",
"utils/json_schema": "utils/json_schema",
+ "utils/math": "utils/math",
"utils/stream": "utils/stream",
"utils/testing": "utils/testing/index",
"utils/tiktoken": "utils/tiktoken",
diff --git a/langchain-core/src/documents/transformers.ts b/langchain-core/src/documents/transformers.ts
index b42ccab2dc16..45b5a6a06607 100644
--- a/langchain-core/src/documents/transformers.ts
+++ b/langchain-core/src/documents/transformers.ts
@@ -36,3 +36,20 @@ export abstract class BaseDocumentTransformer<
return this.transformDocuments(input);
}
}
+
+/**
+ * Class for document transformers that return exactly one transformed document
+ * for each input document.
+ */
+export abstract class MappingDocumentTransformer extends BaseDocumentTransformer {
+ async transformDocuments(documents: Document[]): Promise {
+ const newDocuments = [];
+ for (const document of documents) {
+ const transformedDocument = await this._transformDocument(document);
+ newDocuments.push(transformedDocument);
+ }
+ return newDocuments;
+ }
+
+ abstract _transformDocument(document: Document): Promise;
+}
diff --git a/langchain-core/src/load/import_map.ts b/langchain-core/src/load/import_map.ts
index 40fe9f8af9a4..0c94e2838e41 100644
--- a/langchain-core/src/load/import_map.ts
+++ b/langchain-core/src/load/import_map.ts
@@ -35,6 +35,7 @@ export * as utils__env from "../utils/env.js";
export * as utils__hash from "../utils/hash.js";
export * as utils__json_patch from "../utils/json_patch.js";
export * as utils__json_schema from "../utils/json_schema.js";
+export * as utils__math from "../utils/math.js";
export * as utils__stream from "../utils/stream.js";
export * as utils__testing from "../utils/testing/index.js";
export * as utils__tiktoken from "../utils/tiktoken.js";
diff --git a/langchain-core/src/load/index.ts b/langchain-core/src/load/index.ts
index 69e32bc52cbc..870b7a374f93 100644
--- a/langchain-core/src/load/index.ts
+++ b/langchain-core/src/load/index.ts
@@ -104,15 +104,25 @@ async function reviver(
| (typeof finalImportMap)[keyof typeof finalImportMap]
| OptionalImportMap[keyof OptionalImportMap]
| null = null;
+
+ const optionalImportNamespaceAliases = [namespace.join("/")];
+ if (namespace[0] === "langchain_community") {
+ optionalImportNamespaceAliases.push(
+ ["langchain", ...namespace.slice(1)].join("/")
+ );
+ }
+ const matchingNamespaceAlias = optionalImportNamespaceAliases.find(
+ (alias) => alias in optionalImportsMap
+ );
if (
defaultOptionalImportEntrypoints
.concat(optionalImportEntrypoints)
.includes(namespace.join("/")) ||
- namespace.join("/") in optionalImportsMap
+ matchingNamespaceAlias
) {
- if (namespace.join("/") in optionalImportsMap) {
+ if (matchingNamespaceAlias !== undefined) {
module = await optionalImportsMap[
- namespace.join("/") as keyof typeof optionalImportsMap
+ matchingNamespaceAlias as keyof typeof optionalImportsMap
];
} else {
throw new Error(
@@ -126,6 +136,7 @@ async function reviver(
if (
namespace[0] === "langchain" ||
namespace[0] === "langchain_core" ||
+ namespace[0] === "langchain_community" ||
namespace[0] === "langchain_anthropic" ||
namespace[0] === "langchain_openai"
) {
diff --git a/langchain-core/src/messages/index.ts b/langchain-core/src/messages/index.ts
index 9ddc2fd64e06..2019e67e7620 100644
--- a/langchain-core/src/messages/index.ts
+++ b/langchain-core/src/messages/index.ts
@@ -734,3 +734,29 @@ export function mapStoredMessageToChatMessage(message: StoredMessage) {
throw new Error(`Got unexpected type: ${storedMessage.type}`);
}
}
+
+/**
+ * Transforms an array of `StoredMessage` instances into an array of
+ * `BaseMessage` instances. It uses the `mapV1MessageToStoredMessage`
+ * function to ensure all messages are in the `StoredMessage` format, then
+ * creates new instances of the appropriate `BaseMessage` subclass based
+ * on the type of each message. This function is used to prepare stored
+ * messages for use in a chat context.
+ */
+export function mapStoredMessagesToChatMessages(
+ messages: StoredMessage[]
+): BaseMessage[] {
+ return messages.map(mapStoredMessageToChatMessage);
+}
+
+/**
+ * Transforms an array of `BaseMessage` instances into an array of
+ * `StoredMessage` instances. It does this by calling the `toDict` method
+ * on each `BaseMessage`, which returns a `StoredMessage`. This function
+ * is used to prepare chat messages for storage.
+ */
+export function mapChatMessagesToStoredMessages(
+ messages: BaseMessage[]
+): StoredMessage[] {
+ return messages.map((message) => message.toDict());
+}
diff --git a/langchain-core/src/utils/math.ts b/langchain-core/src/utils/math.ts
new file mode 100644
index 000000000000..fe703c2d5f79
--- /dev/null
+++ b/langchain-core/src/utils/math.ts
@@ -0,0 +1,180 @@
+import {
+ similarity as ml_distance_similarity,
+ distance as ml_distance,
+} from "ml-distance";
+
+type VectorFunction = (xVector: number[], yVector: number[]) => number;
+
+/**
+ * Apply a row-wise function between two matrices with the same number of columns.
+ *
+ * @param {number[][]} X - The first matrix.
+ * @param {number[][]} Y - The second matrix.
+ * @param {VectorFunction} func - The function to apply.
+ *
+ * @throws {Error} If the number of columns in X and Y are not the same.
+ *
+ * @returns {number[][] | [[]]} A matrix where each row represents the result of applying the function between the corresponding rows of X and Y.
+ */
+
+export function matrixFunc(
+ X: number[][],
+ Y: number[][],
+ func: VectorFunction
+): number[][] {
+ if (
+ X.length === 0 ||
+ X[0].length === 0 ||
+ Y.length === 0 ||
+ Y[0].length === 0
+ ) {
+ return [[]];
+ }
+
+ if (X[0].length !== Y[0].length) {
+ throw new Error(
+ `Number of columns in X and Y must be the same. X has shape ${[
+ X.length,
+ X[0].length,
+ ]} and Y has shape ${[Y.length, Y[0].length]}.`
+ );
+ }
+
+ return X.map((xVector) =>
+ Y.map((yVector) => func(xVector, yVector)).map((similarity) =>
+ Number.isNaN(similarity) ? 0 : similarity
+ )
+ );
+}
+
+export function normalize(M: number[][], similarity = false): number[][] {
+ const max = matrixMaxVal(M);
+ return M.map((row) =>
+ row.map((val) => (similarity ? 1 - val / max : val / max))
+ );
+}
+
+/**
+ * This function calculates the row-wise cosine similarity between two matrices with the same number of columns.
+ *
+ * @param {number[][]} X - The first matrix.
+ * @param {number[][]} Y - The second matrix.
+ *
+ * @throws {Error} If the number of columns in X and Y are not the same.
+ *
+ * @returns {number[][] | [[]]} A matrix where each row represents the cosine similarity values between the corresponding rows of X and Y.
+ */
+export function cosineSimilarity(X: number[][], Y: number[][]): number[][] {
+ return matrixFunc(X, Y, ml_distance_similarity.cosine);
+}
+
+export function innerProduct(X: number[][], Y: number[][]): number[][] {
+ return matrixFunc(X, Y, ml_distance.innerProduct);
+}
+
+export function euclideanDistance(X: number[][], Y: number[][]): number[][] {
+ return matrixFunc(X, Y, ml_distance.euclidean);
+}
+
+/**
+ * This function implements the Maximal Marginal Relevance algorithm
+ * to select a set of embeddings that maximizes the diversity and relevance to a query embedding.
+ *
+ * @param {number[]|number[][]} queryEmbedding - The query embedding.
+ * @param {number[][]} embeddingList - The list of embeddings to select from.
+ * @param {number} [lambda=0.5] - The trade-off parameter between relevance and diversity.
+ * @param {number} [k=4] - The maximum number of embeddings to select.
+ *
+ * @returns {number[]} The indexes of the selected embeddings in the embeddingList.
+ */
+export function maximalMarginalRelevance(
+ queryEmbedding: number[] | number[][],
+ embeddingList: number[][],
+ lambda = 0.5,
+ k = 4
+): number[] {
+ if (Math.min(k, embeddingList.length) <= 0) {
+ return [];
+ }
+
+ const queryEmbeddingExpanded = (
+ Array.isArray(queryEmbedding[0]) ? queryEmbedding : [queryEmbedding]
+ ) as number[][];
+
+ const similarityToQuery = cosineSimilarity(
+ queryEmbeddingExpanded,
+ embeddingList
+ )[0];
+ const mostSimilarEmbeddingIndex = argMax(similarityToQuery).maxIndex;
+
+ const selectedEmbeddings = [embeddingList[mostSimilarEmbeddingIndex]];
+ const selectedEmbeddingsIndexes = [mostSimilarEmbeddingIndex];
+
+ while (selectedEmbeddingsIndexes.length < Math.min(k, embeddingList.length)) {
+ let bestScore = -Infinity;
+ let bestIndex = -1;
+
+ const similarityToSelected = cosineSimilarity(
+ embeddingList,
+ selectedEmbeddings
+ );
+
+ similarityToQuery.forEach((queryScore, queryScoreIndex) => {
+ if (selectedEmbeddingsIndexes.includes(queryScoreIndex)) {
+ return;
+ }
+ const maxSimilarityToSelected = Math.max(
+ ...similarityToSelected[queryScoreIndex]
+ );
+ const score =
+ lambda * queryScore - (1 - lambda) * maxSimilarityToSelected;
+
+ if (score > bestScore) {
+ bestScore = score;
+ bestIndex = queryScoreIndex;
+ }
+ });
+ selectedEmbeddings.push(embeddingList[bestIndex]);
+ selectedEmbeddingsIndexes.push(bestIndex);
+ }
+
+ return selectedEmbeddingsIndexes;
+}
+
+type MaxInfo = {
+ maxIndex: number;
+ maxValue: number;
+};
+
+/**
+ * Finds the index of the maximum value in the given array.
+ * @param {number[]} array - The input array.
+ *
+ * @returns {number} The index of the maximum value in the array. If the array is empty, returns -1.
+ */
+function argMax(array: number[]): MaxInfo {
+ if (array.length === 0) {
+ return {
+ maxIndex: -1,
+ maxValue: NaN,
+ };
+ }
+
+ let maxValue = array[0];
+ let maxIndex = 0;
+
+ for (let i = 1; i < array.length; i += 1) {
+ if (array[i] > maxValue) {
+ maxIndex = i;
+ maxValue = array[i];
+ }
+ }
+ return { maxIndex, maxValue };
+}
+
+function matrixMaxVal(arrays: number[][]): number {
+ return arrays.reduce(
+ (acc, array) => Math.max(acc, argMax(array).maxValue),
+ 0
+ );
+}
diff --git a/langchain/src/util/tests/math_utils.test.ts b/langchain-core/src/utils/tests/math_utils.test.ts
similarity index 100%
rename from langchain/src/util/tests/math_utils.test.ts
rename to langchain-core/src/utils/tests/math_utils.test.ts
diff --git a/langchain/package.json b/langchain/package.json
index 5c1b3fe2ce79..b858507fa64a 100644
--- a/langchain/package.json
+++ b/langchain/package.json
@@ -1,6 +1,6 @@
{
"name": "langchain",
- "version": "0.0.203",
+ "version": "0.0.204-rc.0",
"description": "Typescript bindings for langchain",
"type": "module",
"engines": {
@@ -882,10 +882,6 @@
"author": "LangChain",
"license": "MIT",
"devDependencies": {
- "@aws-crypto/sha256-js": "^5.0.0",
- "@aws-sdk/client-bedrock-runtime": "^3.422.0",
- "@aws-sdk/client-dynamodb": "^3.310.0",
- "@aws-sdk/client-kendra": "^3.352.0",
"@aws-sdk/client-lambda": "^3.310.0",
"@aws-sdk/client-s3": "^3.310.0",
"@aws-sdk/client-sagemaker-runtime": "^3.414.0",
@@ -930,7 +926,6 @@
"@tsconfig/recommended": "^1.0.2",
"@types/d3-dsv": "^2",
"@types/decamelize": "^1.2.0",
- "@types/flat": "^5.0.2",
"@types/html-to-text": "^9",
"@types/js-yaml": "^4",
"@types/jsdom": "^21.1.1",
@@ -988,7 +983,6 @@
"llmonitor": "^0.5.9",
"lodash": "^4.17.21",
"mammoth": "^1.5.1",
- "ml-matrix": "^6.10.4",
"mongodb": "^5.2.0",
"mysql2": "^3.3.3",
"neo4j-driver": "^5.12.0",
@@ -1026,10 +1020,6 @@
"youtubei.js": "^5.8.0"
},
"peerDependencies": {
- "@aws-crypto/sha256-js": "^5.0.0",
- "@aws-sdk/client-bedrock-runtime": "^3.422.0",
- "@aws-sdk/client-dynamodb": "^3.310.0",
- "@aws-sdk/client-kendra": "^3.352.0",
"@aws-sdk/client-lambda": "^3.310.0",
"@aws-sdk/client-s3": "^3.310.0",
"@aws-sdk/client-sagemaker-runtime": "^3.310.0",
@@ -1129,18 +1119,6 @@
"youtubei.js": "^5.8.0"
},
"peerDependenciesMeta": {
- "@aws-crypto/sha256-js": {
- "optional": true
- },
- "@aws-sdk/client-bedrock-runtime": {
- "optional": true
- },
- "@aws-sdk/client-dynamodb": {
- "optional": true
- },
- "@aws-sdk/client-kendra": {
- "optional": true
- },
"@aws-sdk/client-lambda": {
"optional": true
},
@@ -1435,17 +1413,17 @@
},
"dependencies": {
"@anthropic-ai/sdk": "^0.9.1",
- "@langchain/core": "~0.0.10",
+ "@langchain/community": "~0.0.0",
+ "@langchain/core": "~0.0.11-rc.1",
+ "@langchain/openai": "~0.0.2-rc.0",
"binary-extensions": "^2.2.0",
"expr-eval": "^2.0.2",
- "flat": "^5.0.2",
"js-tiktoken": "^1.0.7",
"js-yaml": "^4.1.0",
"jsonpointer": "^5.0.1",
"langchainhub": "~0.0.6",
"langsmith": "~0.0.48",
"ml-distance": "^4.0.0",
- "openai": "^4.19.0",
"openapi-types": "^12.1.3",
"p-retry": "4",
"uuid": "^9.0.0",
diff --git a/langchain/scripts/check-tree-shaking.js b/langchain/scripts/check-tree-shaking.js
index 66a1f194199f..bae5213269d7 100644
--- a/langchain/scripts/check-tree-shaking.js
+++ b/langchain/scripts/check-tree-shaking.js
@@ -28,6 +28,7 @@ export function listExternals() {
/node\:/,
/js-tiktoken/,
/@langchain\/core/,
+ /@langchain\/community/,
"axios", // axios is a dependency of openai
"convex",
"convex/server",
diff --git a/langchain/src/agents/openai/output_parser.ts b/langchain/src/agents/openai/output_parser.ts
index 960f6db84e47..fc14b6a4f160 100644
--- a/langchain/src/agents/openai/output_parser.ts
+++ b/langchain/src/agents/openai/output_parser.ts
@@ -1,4 +1,4 @@
-import type { OpenAI as OpenAIClient } from "openai";
+import type { OpenAIClient } from "@langchain/openai";
import {
AgentAction,
AgentFinish,
diff --git a/langchain/src/cache/cloudflare_kv.ts b/langchain/src/cache/cloudflare_kv.ts
index d438c7cd7cc5..b3f86e2b187e 100644
--- a/langchain/src/cache/cloudflare_kv.ts
+++ b/langchain/src/cache/cloudflare_kv.ts
@@ -1,77 +1 @@
-import type { KVNamespace } from "@cloudflare/workers-types";
-
-import { BaseCache, Generation } from "../schema/index.js";
-import {
- getCacheKey,
- serializeGeneration,
- deserializeStoredGeneration,
-} from "./base.js";
-
-/**
- * Represents a specific implementation of a caching mechanism using Cloudflare KV
- * as the underlying storage system. It extends the `BaseCache` class and
- * overrides its methods to provide the Cloudflare KV-specific logic.
- * @example
- * ```typescript
- * // Example of using OpenAI with Cloudflare KV as cache in a Cloudflare Worker
- * const cache = new CloudflareKVCache(env.KV_NAMESPACE);
- * const model = new ChatAnthropic({
- * cache,
- * });
- * const response = await model.invoke("How are you today?");
- * return new Response(JSON.stringify(response), {
- * headers: { "content-type": "application/json" },
- * });
- *
- * ```
- */
-export class CloudflareKVCache extends BaseCache {
- private binding: KVNamespace;
-
- constructor(binding: KVNamespace) {
- super();
- this.binding = binding;
- }
-
- /**
- * Retrieves data from the cache. It constructs a cache key from the given
- * `prompt` and `llmKey`, and retrieves the corresponding value from the
- * Cloudflare KV namespace.
- * @param prompt The prompt used to construct the cache key.
- * @param llmKey The LLM key used to construct the cache key.
- * @returns An array of Generations if found, null otherwise.
- */
- public async lookup(prompt: string, llmKey: string) {
- let idx = 0;
- let key = getCacheKey(prompt, llmKey, String(idx));
- let value = await this.binding.get(key);
- const generations: Generation[] = [];
-
- while (value) {
- generations.push(deserializeStoredGeneration(JSON.parse(value)));
- idx += 1;
- key = getCacheKey(prompt, llmKey, String(idx));
- value = await this.binding.get(key);
- }
-
- return generations.length > 0 ? generations : null;
- }
-
- /**
- * Updates the cache with new data. It constructs a cache key from the
- * given `prompt` and `llmKey`, and stores the `value` in the Cloudflare KV
- * namespace.
- * @param prompt The prompt used to construct the cache key.
- * @param llmKey The LLM key used to construct the cache key.
- * @param value The value to be stored in the cache.
- */
- public async update(prompt: string, llmKey: string, value: Generation[]) {
- for (let i = 0; i < value.length; i += 1) {
- const key = getCacheKey(prompt, llmKey, String(i));
- await this.binding.put(
- key,
- JSON.stringify(serializeGeneration(value[i]))
- );
- }
- }
-}
+export * from "@langchain/community/caches/cloudflare_kv";
diff --git a/langchain/src/cache/momento.ts b/langchain/src/cache/momento.ts
index 3c452a429e45..0a24cf70f21b 100644
--- a/langchain/src/cache/momento.ts
+++ b/langchain/src/cache/momento.ts
@@ -1,173 +1 @@
-/* eslint-disable no-instanceof/no-instanceof */
-import {
- ICacheClient,
- CacheGet,
- CacheSet,
- InvalidArgumentError,
-} from "@gomomento/sdk-core";
-
-import { BaseCache, Generation } from "../schema/index.js";
-import {
- deserializeStoredGeneration,
- getCacheKey,
- serializeGeneration,
-} from "./base.js";
-import { ensureCacheExists } from "../util/momento.js";
-
-/**
- * The settings to instantiate the Momento standard cache.
- */
-export interface MomentoCacheProps {
- /**
- * The Momento cache client.
- */
- client: ICacheClient;
- /**
- * The name of the cache to use to store the data.
- */
- cacheName: string;
- /**
- * The time to live for the cache items. If not specified,
- * the cache client default is used.
- */
- ttlSeconds?: number;
- /**
- * If true, ensure that the cache exists before returning.
- * If false, the cache is not checked for existence.
- * Defaults to true.
- */
- ensureCacheExists?: true;
-}
-
-/**
- * A cache that uses Momento as the backing store.
- * See https://gomomento.com.
- * @example
- * ```typescript
- * const cache = new MomentoCache({
- * client: new CacheClient({
- * configuration: Configurations.Laptop.v1(),
- * credentialProvider: CredentialProvider.fromEnvironmentVariable({
- * environmentVariableName: "MOMENTO_API_KEY",
- * }),
- * defaultTtlSeconds: 60 * 60 * 24, // Cache TTL set to 24 hours.
- * }),
- * cacheName: "langchain",
- * });
- * // Initialize the OpenAI model with Momento cache for caching responses
- * const model = new ChatOpenAI({
- * cache,
- * });
- * await model.invoke("How are you today?");
- * const cachedValues = await cache.lookup("How are you today?", "llmKey");
- * ```
- */
-export class MomentoCache extends BaseCache {
- private client: ICacheClient;
-
- private readonly cacheName: string;
-
- private readonly ttlSeconds?: number;
-
- private constructor(props: MomentoCacheProps) {
- super();
- this.client = props.client;
- this.cacheName = props.cacheName;
-
- this.validateTtlSeconds(props.ttlSeconds);
- this.ttlSeconds = props.ttlSeconds;
- }
-
- /**
- * Create a new standard cache backed by Momento.
- *
- * @param {MomentoCacheProps} props The settings to instantiate the cache.
- * @param {ICacheClient} props.client The Momento cache client.
- * @param {string} props.cacheName The name of the cache to use to store the data.
- * @param {number} props.ttlSeconds The time to live for the cache items. If not specified,
- * the cache client default is used.
- * @param {boolean} props.ensureCacheExists If true, ensure that the cache exists before returning.
- * If false, the cache is not checked for existence. Defaults to true.
- * @throws {@link InvalidArgumentError} if {@link props.ttlSeconds} is not strictly positive.
- * @returns The Momento-backed cache.
- */
- public static async fromProps(
- props: MomentoCacheProps
- ): Promise {
- const instance = new MomentoCache(props);
- if (props.ensureCacheExists || props.ensureCacheExists === undefined) {
- await ensureCacheExists(props.client, props.cacheName);
- }
- return instance;
- }
-
- /**
- * Validate the user-specified TTL, if provided, is strictly positive.
- * @param ttlSeconds The TTL to validate.
- */
- private validateTtlSeconds(ttlSeconds?: number): void {
- if (ttlSeconds !== undefined && ttlSeconds <= 0) {
- throw new InvalidArgumentError("ttlSeconds must be positive.");
- }
- }
-
- /**
- * Lookup LLM generations in cache by prompt and associated LLM key.
- * @param prompt The prompt to lookup.
- * @param llmKey The LLM key to lookup.
- * @returns The generations associated with the prompt and LLM key, or null if not found.
- */
- public async lookup(
- prompt: string,
- llmKey: string
- ): Promise {
- const key = getCacheKey(prompt, llmKey);
- const getResponse = await this.client.get(this.cacheName, key);
-
- if (getResponse instanceof CacheGet.Hit) {
- const value = getResponse.valueString();
- const parsedValue = JSON.parse(value);
- if (!Array.isArray(parsedValue)) {
- return null;
- }
- return JSON.parse(value).map(deserializeStoredGeneration);
- } else if (getResponse instanceof CacheGet.Miss) {
- return null;
- } else if (getResponse instanceof CacheGet.Error) {
- throw getResponse.innerException();
- } else {
- throw new Error(`Unknown response type: ${getResponse.toString()}`);
- }
- }
-
- /**
- * Update the cache with the given generations.
- *
- * Note this overwrites any existing generations for the given prompt and LLM key.
- *
- * @param prompt The prompt to update.
- * @param llmKey The LLM key to update.
- * @param value The generations to store.
- */
- public async update(
- prompt: string,
- llmKey: string,
- value: Generation[]
- ): Promise {
- const key = getCacheKey(prompt, llmKey);
- const setResponse = await this.client.set(
- this.cacheName,
- key,
- JSON.stringify(value.map(serializeGeneration)),
- { ttl: this.ttlSeconds }
- );
-
- if (setResponse instanceof CacheSet.Success) {
- // pass
- } else if (setResponse instanceof CacheSet.Error) {
- throw setResponse.innerException();
- } else {
- throw new Error(`Unknown response type: ${setResponse.toString()}`);
- }
- }
-}
+export * from "@langchain/community/caches/momento";
diff --git a/langchain/src/cache/upstash_redis.ts b/langchain/src/cache/upstash_redis.ts
index 7f1660d6606d..8e1a82be82e3 100644
--- a/langchain/src/cache/upstash_redis.ts
+++ b/langchain/src/cache/upstash_redis.ts
@@ -1,91 +1 @@
-import { Redis, type RedisConfigNodejs } from "@upstash/redis";
-
-import { BaseCache, Generation, StoredGeneration } from "../schema/index.js";
-import {
- deserializeStoredGeneration,
- getCacheKey,
- serializeGeneration,
-} from "./base.js";
-
-export type UpstashRedisCacheProps = {
- /**
- * The config to use to instantiate an Upstash Redis client.
- */
- config?: RedisConfigNodejs;
- /**
- * An existing Upstash Redis client.
- */
- client?: Redis;
-};
-
-/**
- * A cache that uses Upstash as the backing store.
- * See https://docs.upstash.com/redis.
- * @example
- * ```typescript
- * const cache = new UpstashRedisCache({
- * config: {
- * url: "UPSTASH_REDIS_REST_URL",
- * token: "UPSTASH_REDIS_REST_TOKEN",
- * },
- * });
- * // Initialize the OpenAI model with Upstash Redis cache for caching responses
- * const model = new ChatOpenAI({
- * cache,
- * });
- * await model.invoke("How are you today?");
- * const cachedValues = await cache.lookup("How are you today?", "llmKey");
- * ```
- */
-export class UpstashRedisCache extends BaseCache {
- private redisClient: Redis;
-
- constructor(props: UpstashRedisCacheProps) {
- super();
- const { config, client } = props;
-
- if (client) {
- this.redisClient = client;
- } else if (config) {
- this.redisClient = new Redis(config);
- } else {
- throw new Error(
- `Upstash Redis caches require either a config object or a pre-configured client.`
- );
- }
- }
-
- /**
- * Lookup LLM generations in cache by prompt and associated LLM key.
- */
- public async lookup(prompt: string, llmKey: string) {
- let idx = 0;
- let key = getCacheKey(prompt, llmKey, String(idx));
- let value = await this.redisClient.get(key);
- const generations: Generation[] = [];
-
- while (value) {
- generations.push(deserializeStoredGeneration(value));
- idx += 1;
- key = getCacheKey(prompt, llmKey, String(idx));
- value = await this.redisClient.get(key);
- }
-
- return generations.length > 0 ? generations : null;
- }
-
- /**
- * Update the cache with the given generations.
- *
- * Note this overwrites any existing generations for the given prompt and LLM key.
- */
- public async update(prompt: string, llmKey: string, value: Generation[]) {
- for (let i = 0; i < value.length; i += 1) {
- const key = getCacheKey(prompt, llmKey, String(i));
- await this.redisClient.set(
- key,
- JSON.stringify(serializeGeneration(value[i]))
- );
- }
- }
-}
+export * from "@langchain/community/caches/upstash_redis";
diff --git a/langchain/src/callbacks/handlers/llmonitor.ts b/langchain/src/callbacks/handlers/llmonitor.ts
index 9453d62ed7ef..92fe3e48f946 100644
--- a/langchain/src/callbacks/handlers/llmonitor.ts
+++ b/langchain/src/callbacks/handlers/llmonitor.ts
@@ -1,340 +1 @@
-import monitor from "llmonitor";
-import { LLMonitorOptions, ChatMessage, cJSON } from "llmonitor/types";
-
-import { BaseRun, RunUpdate as BaseRunUpdate, KVMap } from "langsmith/schemas";
-
-import { getEnvironmentVariable } from "../../util/env.js";
-
-import {
- BaseMessage,
- ChainValues,
- Generation,
- LLMResult,
-} from "../../schema/index.js";
-import { Serialized } from "../../load/serializable.js";
-
-import { BaseCallbackHandler, BaseCallbackHandlerInput } from "../base.js";
-
-type Role = "user" | "ai" | "system" | "function" | "tool";
-
-// Langchain Helpers
-// Input can be either a single message, an array of message, or an array of array of messages (batch requests)
-
-const parseRole = (id: string[]): Role => {
- const roleHint = id[id.length - 1];
-
- if (roleHint.includes("Human")) return "user";
- if (roleHint.includes("System")) return "system";
- if (roleHint.includes("AI")) return "ai";
- if (roleHint.includes("Function")) return "function";
- if (roleHint.includes("Tool")) return "tool";
-
- return "ai";
-};
-
-type Message = BaseMessage | Generation | string;
-
-type OutputMessage = ChatMessage | string;
-
-const PARAMS_TO_CAPTURE = [
- "stop",
- "stop_sequences",
- "function_call",
- "functions",
- "tools",
- "tool_choice",
- "response_format",
-];
-
-export const convertToLLMonitorMessages = (
- input: Message | Message[] | Message[][]
-): OutputMessage | OutputMessage[] | OutputMessage[][] => {
- const parseMessage = (raw: Message): OutputMessage => {
- if (typeof raw === "string") return raw;
- // sometimes the message is nested in a "message" property
- if ("message" in raw) return parseMessage(raw.message as Message);
-
- // Serialize
- const message = JSON.parse(JSON.stringify(raw));
-
- try {
- // "id" contains an array describing the constructor, with last item actual schema type
- const role = parseRole(message.id);
-
- const obj = message.kwargs;
- const text = message.text ?? obj.content;
-
- return {
- role,
- text,
- ...(obj.additional_kwargs ?? {}),
- };
- } catch (e) {
- // if parsing fails, return the original message
- return message.text ?? message;
- }
- };
-
- if (Array.isArray(input)) {
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore Confuses the compiler
- return input.length === 1
- ? convertToLLMonitorMessages(input[0])
- : input.map(convertToLLMonitorMessages);
- }
- return parseMessage(input);
-};
-
-const parseInput = (rawInput: Record) => {
- if (!rawInput) return null;
-
- const { input, inputs, question } = rawInput;
-
- if (input) return input;
- if (inputs) return inputs;
- if (question) return question;
-
- return rawInput;
-};
-
-const parseOutput = (rawOutput: Record) => {
- if (!rawOutput) return null;
-
- const { text, output, answer, result } = rawOutput;
-
- if (text) return text;
- if (answer) return answer;
- if (output) return output;
- if (result) return result;
-
- return rawOutput;
-};
-
-const parseExtraAndName = (
- llm: Serialized,
- extraParams?: KVMap,
- metadata?: KVMap
-) => {
- const params = {
- ...(extraParams?.invocation_params ?? {}),
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore this is a valid property
- ...(llm?.kwargs ?? {}),
- ...(metadata || {}),
- };
-
- const { model, model_name, modelName, model_id, userId, userProps, ...rest } =
- params;
-
- const name = model || modelName || model_name || model_id || llm.id.at(-1);
-
- // Filter rest to only include params we want to capture
- const extra = Object.fromEntries(
- Object.entries(rest).filter(
- ([key]) =>
- PARAMS_TO_CAPTURE.includes(key) ||
- ["string", "number", "boolean"].includes(typeof rest[key])
- )
- ) as cJSON;
-
- return { name, extra, userId, userProps };
-};
-
-export interface Run extends BaseRun {
- id: string;
- child_runs: this[];
- child_execution_order: number;
-}
-
-export interface RunUpdate extends BaseRunUpdate {
- events: BaseRun["events"];
-}
-
-export interface LLMonitorHandlerFields
- extends BaseCallbackHandlerInput,
- LLMonitorOptions {}
-
-export class LLMonitorHandler
- extends BaseCallbackHandler
- implements LLMonitorHandlerFields
-{
- name = "llmonitor_handler";
-
- monitor: typeof monitor;
-
- constructor(fields: LLMonitorHandlerFields = {}) {
- super(fields);
-
- this.monitor = monitor;
-
- if (fields) {
- const { appId, apiUrl, verbose } = fields;
-
- this.monitor.init({
- verbose,
- appId: appId ?? getEnvironmentVariable("LLMONITOR_APP_ID"),
- apiUrl: apiUrl ?? getEnvironmentVariable("LLMONITOR_API_URL"),
- });
- }
- }
-
- async handleLLMStart(
- llm: Serialized,
- prompts: string[],
- runId: string,
- parentRunId?: string,
- extraParams?: KVMap,
- tags?: string[],
- metadata?: KVMap
- ): Promise {
- const { name, extra, userId, userProps } = parseExtraAndName(
- llm,
- extraParams,
- metadata
- );
-
- await this.monitor.trackEvent("llm", "start", {
- runId,
- parentRunId,
- name,
- input: convertToLLMonitorMessages(prompts),
- extra,
- userId,
- userProps,
- tags,
- runtime: "langchain-js",
- });
- }
-
- async handleChatModelStart(
- llm: Serialized,
- messages: BaseMessage[][],
- runId: string,
- parentRunId?: string,
- extraParams?: KVMap,
- tags?: string[],
- metadata?: KVMap
- ): Promise {
- const { name, extra, userId, userProps } = parseExtraAndName(
- llm,
- extraParams,
- metadata
- );
-
- await this.monitor.trackEvent("llm", "start", {
- runId,
- parentRunId,
- name,
- input: convertToLLMonitorMessages(messages),
- extra,
- userId,
- userProps,
- tags,
- runtime: "langchain-js",
- });
- }
-
- async handleLLMEnd(output: LLMResult, runId: string): Promise {
- const { generations, llmOutput } = output;
-
- await this.monitor.trackEvent("llm", "end", {
- runId,
- output: convertToLLMonitorMessages(generations),
- tokensUsage: {
- completion: llmOutput?.tokenUsage?.completionTokens,
- prompt: llmOutput?.tokenUsage?.promptTokens,
- },
- });
- }
-
- async handleLLMError(error: Error, runId: string): Promise {
- await this.monitor.trackEvent("llm", "error", {
- runId,
- error,
- });
- }
-
- async handleChainStart(
- chain: Serialized,
- inputs: ChainValues,
- runId: string,
- parentRunId?: string,
- tags?: string[],
- metadata?: KVMap
- ): Promise {
- const { agentName, userId, userProps, ...rest } = metadata || {};
-
- // allow the user to specify an agent name
- const name = agentName || chain.id.at(-1);
-
- // Attempt to automatically detect if this is an agent or chain
- const runType =
- agentName || ["AgentExecutor", "PlanAndExecute"].includes(name)
- ? "agent"
- : "chain";
-
- await this.monitor.trackEvent(runType, "start", {
- runId,
- parentRunId,
- name,
- userId,
- userProps,
- input: parseInput(inputs) as cJSON,
- extra: rest,
- tags,
- runtime: "langchain-js",
- });
- }
-
- async handleChainEnd(outputs: ChainValues, runId: string): Promise {
- await this.monitor.trackEvent("chain", "end", {
- runId,
- output: parseOutput(outputs) as cJSON,
- });
- }
-
- async handleChainError(error: Error, runId: string): Promise {
- await this.monitor.trackEvent("chain", "error", {
- runId,
- error,
- });
- }
-
- async handleToolStart(
- tool: Serialized,
- input: string,
- runId: string,
- parentRunId?: string,
- tags?: string[],
- metadata?: KVMap
- ): Promise {
- const { toolName, userId, userProps, ...rest } = metadata || {};
- const name = toolName || tool.id.at(-1);
-
- await this.monitor.trackEvent("tool", "start", {
- runId,
- parentRunId,
- name,
- userId,
- userProps,
- input,
- extra: rest,
- tags,
- runtime: "langchain-js",
- });
- }
-
- async handleToolEnd(output: string, runId: string): Promise {
- await this.monitor.trackEvent("tool", "end", {
- runId,
- output,
- });
- }
-
- async handleToolError(error: Error, runId: string): Promise {
- await this.monitor.trackEvent("tool", "error", {
- runId,
- error,
- });
- }
-}
+export * from "@langchain/community/callbacks/handlers/llmonitor";
diff --git a/langchain/src/callbacks/tests/llmonitor.int.test.ts b/langchain/src/callbacks/tests/llmonitor.int.test.ts
index eb796840d66c..62c589f501d8 100644
--- a/langchain/src/callbacks/tests/llmonitor.int.test.ts
+++ b/langchain/src/callbacks/tests/llmonitor.int.test.ts
@@ -16,7 +16,7 @@ import { Calculator } from "../../tools/calculator.js";
import { initializeAgentExecutorWithOptions } from "../../agents/initialize.js";
-test("Test traced agent with openai functions", async () => {
+test.skip("Test traced agent with openai functions", async () => {
const tools = [new Calculator()];
const chat = new ChatOpenAI({ modelName: "gpt-3.5-turbo", temperature: 0 });
@@ -41,7 +41,7 @@ test("Test traced agent with openai functions", async () => {
console.log(result);
});
-test("Test traced chain with tags", async () => {
+test.skip("Test traced chain with tags", async () => {
const llm = new OpenAI();
const qaPrompt = new PromptTemplate({
template: "Q: {question} A:",
@@ -75,7 +75,7 @@ test("Test traced chain with tags", async () => {
);
});
-test("Test traced chat call with tags", async () => {
+test.skip("Test traced chat call with tags", async () => {
const chat = new ChatOpenAI({
callbacks: [new LLMonitorHandler({ verbose: true })],
});
diff --git a/langchain/src/chains/openai_functions/openapi.ts b/langchain/src/chains/openai_functions/openapi.ts
index 06eb92ad4995..5306eef626db 100644
--- a/langchain/src/chains/openai_functions/openapi.ts
+++ b/langchain/src/chains/openai_functions/openapi.ts
@@ -1,4 +1,4 @@
-import type { OpenAI as OpenAIClient } from "openai";
+import type { OpenAIClient } from "@langchain/openai";
import { JsonSchema7ObjectType } from "zod-to-json-schema/src/parsers/object.js";
import { JsonSchema7ArrayType } from "zod-to-json-schema/src/parsers/array.js";
import { JsonSchema7Type } from "zod-to-json-schema/src/parseDef.js";
diff --git a/langchain/src/chains/openai_moderation.ts b/langchain/src/chains/openai_moderation.ts
index 862552099405..2474baaab0ba 100644
--- a/langchain/src/chains/openai_moderation.ts
+++ b/langchain/src/chains/openai_moderation.ts
@@ -1,4 +1,4 @@
-import { type ClientOptions, OpenAI as OpenAIClient } from "openai";
+import { type ClientOptions, OpenAIClient } from "@langchain/openai";
import { BaseChain, ChainInputs } from "./base.js";
import { ChainValues } from "../schema/index.js";
import { AsyncCaller, AsyncCallerParams } from "../util/async_caller.js";
diff --git a/langchain/src/chat_models/baiduwenxin.ts b/langchain/src/chat_models/baiduwenxin.ts
index 060da0298e76..61ffe21de4d4 100644
--- a/langchain/src/chat_models/baiduwenxin.ts
+++ b/langchain/src/chat_models/baiduwenxin.ts
@@ -1,542 +1 @@
-import { BaseChatModel, BaseChatModelParams } from "./base.js";
-import {
- AIMessage,
- BaseMessage,
- ChatGeneration,
- ChatMessage,
- ChatResult,
-} from "../schema/index.js";
-import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import { getEnvironmentVariable } from "../util/env.js";
-
-/**
- * Type representing the role of a message in the Wenxin chat model.
- */
-export type WenxinMessageRole = "assistant" | "user";
-
-/**
- * Interface representing a message in the Wenxin chat model.
- */
-interface WenxinMessage {
- role: WenxinMessageRole;
- content: string;
-}
-
-/**
- * Interface representing the usage of tokens in a chat completion.
- */
-interface TokenUsage {
- completionTokens?: number;
- promptTokens?: number;
- totalTokens?: number;
-}
-
-/**
- * Interface representing a request for a chat completion.
- */
-interface ChatCompletionRequest {
- messages: WenxinMessage[];
- stream?: boolean;
- user_id?: string;
- temperature?: number;
- top_p?: number;
- penalty_score?: number;
- system?: string;
-}
-
-/**
- * Interface representing a response from a chat completion.
- */
-interface ChatCompletionResponse {
- id: string;
- object: string;
- created: number;
- result: string;
- need_clear_history: boolean;
- usage: TokenUsage;
-}
-
-/**
- * Interface defining the input to the ChatBaiduWenxin class.
- */
-declare interface BaiduWenxinChatInput {
- /** Model name to use. Available options are: ERNIE-Bot, ERNIE-Bot-turbo, ERNIE-Bot-4
- * @default "ERNIE-Bot-turbo"
- */
- modelName: string;
-
- /** Whether to stream the results or not. Defaults to false. */
- streaming?: boolean;
-
- /** Messages to pass as a prefix to the prompt */
- prefixMessages?: WenxinMessage[];
-
- /**
- * ID of the end-user who made requests.
- */
- userId?: string;
-
- /**
- * API key to use when making requests. Defaults to the value of
- * `BAIDU_API_KEY` environment variable.
- */
- baiduApiKey?: string;
-
- /**
- * Secret key to use when making requests. Defaults to the value of
- * `BAIDU_SECRET_KEY` environment variable.
- */
- baiduSecretKey?: string;
-
- /** Amount of randomness injected into the response. Ranges
- * from 0 to 1 (0 is not included). Use temp closer to 0 for analytical /
- * multiple choice, and temp closer to 1 for creative
- * and generative tasks. Defaults to 0.95.
- */
- temperature?: number;
-
- /** Total probability mass of tokens to consider at each step. Range
- * from 0 to 1.0. Defaults to 0.8.
- */
- topP?: number;
-
- /** Penalizes repeated tokens according to frequency. Range
- * from 1.0 to 2.0. Defaults to 1.0.
- */
- penaltyScore?: number;
-}
-
-/**
- * Function that extracts the custom role of a generic chat message.
- * @param message Chat message from which to extract the custom role.
- * @returns The custom role of the chat message.
- */
-function extractGenericMessageCustomRole(message: ChatMessage) {
- if (message.role !== "assistant" && message.role !== "user") {
- console.warn(`Unknown message role: ${message.role}`);
- }
-
- return message.role as WenxinMessageRole;
-}
-
-/**
- * Function that converts a base message to a Wenxin message role.
- * @param message Base message to convert.
- * @returns The Wenxin message role.
- */
-function messageToWenxinRole(message: BaseMessage): WenxinMessageRole {
- const type = message._getType();
- switch (type) {
- case "ai":
- return "assistant";
- case "human":
- return "user";
- case "system":
- throw new Error("System messages should not be here");
- case "function":
- throw new Error("Function messages not supported");
- case "generic": {
- if (!ChatMessage.isInstance(message))
- throw new Error("Invalid generic chat message");
- return extractGenericMessageCustomRole(message);
- }
- default:
- throw new Error(`Unknown message type: ${type}`);
- }
-}
-
-/**
- * Wrapper around Baidu ERNIE large language models that use the Chat endpoint.
- *
- * To use you should have the `BAIDU_API_KEY` and `BAIDU_SECRET_KEY`
- * environment variable set.
- *
- * @augments BaseLLM
- * @augments BaiduERNIEInput
- * @example
- * ```typescript
- * const ernieTurbo = new ChatBaiduWenxin({
- * baiduApiKey: "YOUR-API-KEY",
- * baiduSecretKey: "YOUR-SECRET-KEY",
- * });
- *
- * const ernie = new ChatBaiduWenxin({
- * modelName: "ERNIE-Bot",
- * temperature: 1,
- * baiduApiKey: "YOUR-API-KEY",
- * baiduSecretKey: "YOUR-SECRET-KEY",
- * });
- *
- * const messages = [new HumanMessage("Hello")];
- *
- * let res = await ernieTurbo.call(messages);
- *
- * res = await ernie.call(messages);
- * ```
- */
-export class ChatBaiduWenxin
- extends BaseChatModel
- implements BaiduWenxinChatInput
-{
- static lc_name() {
- return "ChatBaiduWenxin";
- }
-
- get callKeys(): string[] {
- return ["stop", "signal", "options"];
- }
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- baiduApiKey: "BAIDU_API_KEY",
- baiduSecretKey: "BAIDU_SECRET_KEY",
- };
- }
-
- get lc_aliases(): { [key: string]: string } | undefined {
- return undefined;
- }
-
- lc_serializable = true;
-
- baiduApiKey?: string;
-
- baiduSecretKey?: string;
-
- accessToken: string;
-
- streaming = false;
-
- prefixMessages?: WenxinMessage[];
-
- userId?: string;
-
- modelName = "ERNIE-Bot-turbo";
-
- apiUrl: string;
-
- temperature?: number | undefined;
-
- topP?: number | undefined;
-
- penaltyScore?: number | undefined;
-
- constructor(fields?: Partial & BaseChatModelParams) {
- super(fields ?? {});
-
- this.baiduApiKey =
- fields?.baiduApiKey ?? getEnvironmentVariable("BAIDU_API_KEY");
- if (!this.baiduApiKey) {
- throw new Error("Baidu API key not found");
- }
-
- this.baiduSecretKey =
- fields?.baiduSecretKey ?? getEnvironmentVariable("BAIDU_SECRET_KEY");
- if (!this.baiduSecretKey) {
- throw new Error("Baidu Secret key not found");
- }
-
- this.streaming = fields?.streaming ?? this.streaming;
- this.prefixMessages = fields?.prefixMessages ?? this.prefixMessages;
- this.userId = fields?.userId ?? this.userId;
- this.temperature = fields?.temperature ?? this.temperature;
- this.topP = fields?.topP ?? this.topP;
- this.penaltyScore = fields?.penaltyScore ?? this.penaltyScore;
-
- this.modelName = fields?.modelName ?? this.modelName;
-
- if (this.modelName === "ERNIE-Bot") {
- this.apiUrl =
- "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions";
- } else if (this.modelName === "ERNIE-Bot-turbo") {
- this.apiUrl =
- "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant";
- } else if (this.modelName === "ERNIE-Bot-4") {
- this.apiUrl =
- "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro";
- } else {
- throw new Error(`Invalid model name: ${this.modelName}`);
- }
- }
-
- /**
- * Method that retrieves the access token for making requests to the Baidu
- * API.
- * @param options Optional parsed call options.
- * @returns The access token for making requests to the Baidu API.
- */
- async getAccessToken(options?: this["ParsedCallOptions"]) {
- const url = `https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=${this.baiduApiKey}&client_secret=${this.baiduSecretKey}`;
- const response = await fetch(url, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- Accept: "application/json",
- },
- signal: options?.signal,
- });
- if (!response.ok) {
- const text = await response.text();
- const error = new Error(
- `Baidu get access token failed with status code ${response.status}, response: ${text}`
- );
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- (error as any).response = response;
- throw error;
- }
- const json = await response.json();
- return json.access_token;
- }
-
- /**
- * Get the parameters used to invoke the model
- */
- invocationParams(): Omit {
- return {
- stream: this.streaming,
- user_id: this.userId,
- temperature: this.temperature,
- top_p: this.topP,
- penalty_score: this.penaltyScore,
- };
- }
-
- /**
- * Get the identifying parameters for the model
- */
- identifyingParams() {
- return {
- model_name: this.modelName,
- ...this.invocationParams(),
- };
- }
-
- /** @ignore */
- async _generate(
- messages: BaseMessage[],
- options?: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): Promise {
- const tokenUsage: TokenUsage = {};
-
- const params = this.invocationParams();
-
- // Wenxin requires the system message to be put in the params, not messages array
- const systemMessage = messages.find(
- (message) => message._getType() === "system"
- );
- if (systemMessage) {
- // eslint-disable-next-line no-param-reassign
- messages = messages.filter((message) => message !== systemMessage);
- params.system = systemMessage.text;
- }
- const messagesMapped: WenxinMessage[] = messages.map((message) => ({
- role: messageToWenxinRole(message),
- content: message.text,
- }));
-
- const data = params.stream
- ? await new Promise((resolve, reject) => {
- let response: ChatCompletionResponse;
- let rejected = false;
- let resolved = false;
- this.completionWithRetry(
- {
- ...params,
- messages: messagesMapped,
- },
- true,
- options?.signal,
- (event) => {
- const data = JSON.parse(event.data);
-
- if (data?.error_code) {
- if (rejected) {
- return;
- }
- rejected = true;
- reject(new Error(data?.error_msg));
- return;
- }
-
- const message = data as {
- id: string;
- object: string;
- created: number;
- sentence_id?: number;
- is_end: boolean;
- result: string;
- need_clear_history: boolean;
- usage: TokenUsage;
- };
-
- // on the first message set the response properties
- if (!response) {
- response = {
- id: message.id,
- object: message.object,
- created: message.created,
- result: message.result,
- need_clear_history: message.need_clear_history,
- usage: message.usage,
- };
- } else {
- response.result += message.result;
- response.created = message.created;
- response.need_clear_history = message.need_clear_history;
- response.usage = message.usage;
- }
-
- // TODO this should pass part.index to the callback
- // when that's supported there
- // eslint-disable-next-line no-void
- void runManager?.handleLLMNewToken(message.result ?? "");
-
- if (message.is_end) {
- if (resolved || rejected) {
- return;
- }
- resolved = true;
- resolve(response);
- }
- }
- ).catch((error) => {
- if (!rejected) {
- rejected = true;
- reject(error);
- }
- });
- })
- : await this.completionWithRetry(
- {
- ...params,
- messages: messagesMapped,
- },
- false,
- options?.signal
- ).then((data) => {
- if (data?.error_code) {
- throw new Error(data?.error_msg);
- }
- return data;
- });
-
- const {
- completion_tokens: completionTokens,
- prompt_tokens: promptTokens,
- total_tokens: totalTokens,
- } = data.usage ?? {};
-
- if (completionTokens) {
- tokenUsage.completionTokens =
- (tokenUsage.completionTokens ?? 0) + completionTokens;
- }
-
- if (promptTokens) {
- tokenUsage.promptTokens = (tokenUsage.promptTokens ?? 0) + promptTokens;
- }
-
- if (totalTokens) {
- tokenUsage.totalTokens = (tokenUsage.totalTokens ?? 0) + totalTokens;
- }
-
- const generations: ChatGeneration[] = [];
- const text = data.result ?? "";
- generations.push({
- text,
- message: new AIMessage(text),
- });
- return {
- generations,
- llmOutput: { tokenUsage },
- };
- }
-
- /** @ignore */
- async completionWithRetry(
- request: ChatCompletionRequest,
- stream: boolean,
- signal?: AbortSignal,
- onmessage?: (event: MessageEvent) => void
- ) {
- // The first run will get the accessToken
- if (!this.accessToken) {
- this.accessToken = await this.getAccessToken();
- }
-
- const makeCompletionRequest = async () => {
- const url = `${this.apiUrl}?access_token=${this.accessToken}`;
- const response = await fetch(url, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify(request),
- signal,
- });
-
- if (!stream) {
- return response.json();
- } else {
- if (response.body) {
- // response will not be a stream if an error occurred
- if (
- !response.headers
- .get("content-type")
- ?.startsWith("text/event-stream")
- ) {
- onmessage?.(
- new MessageEvent("message", {
- data: await response.text(),
- })
- );
- return;
- }
-
- const reader = response.body.getReader();
-
- const decoder = new TextDecoder("utf-8");
- let data = "";
-
- let continueReading = true;
- while (continueReading) {
- const { done, value } = await reader.read();
- if (done) {
- continueReading = false;
- break;
- }
- data += decoder.decode(value);
-
- let continueProcessing = true;
- while (continueProcessing) {
- const newlineIndex = data.indexOf("\n");
- if (newlineIndex === -1) {
- continueProcessing = false;
- break;
- }
- const line = data.slice(0, newlineIndex);
- data = data.slice(newlineIndex + 1);
-
- if (line.startsWith("data:")) {
- const event = new MessageEvent("message", {
- data: line.slice("data:".length).trim(),
- });
- onmessage?.(event);
- }
- }
- }
- }
- }
- };
- return this.caller.call(makeCompletionRequest);
- }
-
- _llmType() {
- return "baiduwenxin";
- }
-
- /** @ignore */
- _combineLLMOutput() {
- return [];
- }
-}
+export * from "@langchain/community/chat_models/baiduwenxin";
diff --git a/langchain/src/chat_models/bedrock/index.ts b/langchain/src/chat_models/bedrock/index.ts
index 04fabc096d00..a78523c28a2b 100644
--- a/langchain/src/chat_models/bedrock/index.ts
+++ b/langchain/src/chat_models/bedrock/index.ts
@@ -1,38 +1 @@
-import { defaultProvider } from "@aws-sdk/credential-provider-node";
-import { BaseBedrockInput } from "../../util/bedrock.js";
-import { BedrockChat as BaseBedrockChat } from "./web.js";
-import { BaseChatModelParams } from "../base.js";
-
-/**
- * @example
- * ```typescript
- * const model = new BedrockChat({
- * model: "anthropic.claude-v2",
- * region: "us-east-1",
- * });
- * const res = await model.invoke([{ content: "Tell me a joke" }]);
- * console.log(res);
- * ```
- */
-export class BedrockChat extends BaseBedrockChat {
- static lc_name() {
- return "BedrockChat";
- }
-
- constructor(fields?: Partial & BaseChatModelParams) {
- super({
- ...fields,
- credentials: fields?.credentials ?? defaultProvider(),
- });
- }
-}
-
-export {
- convertMessagesToPromptAnthropic,
- convertMessagesToPrompt,
-} from "./web.js";
-
-/**
- * @deprecated Use `BedrockChat` instead.
- */
-export const ChatBedrock = BedrockChat;
+export * from "@langchain/community/chat_models/bedrock";
diff --git a/langchain/src/chat_models/bedrock/web.ts b/langchain/src/chat_models/bedrock/web.ts
index 0431f5baa359..9ef97f768f8a 100644
--- a/langchain/src/chat_models/bedrock/web.ts
+++ b/langchain/src/chat_models/bedrock/web.ts
@@ -1,431 +1 @@
-import { SignatureV4 } from "@smithy/signature-v4";
-import { HttpRequest } from "@smithy/protocol-http";
-import { EventStreamCodec } from "@smithy/eventstream-codec";
-import { fromUtf8, toUtf8 } from "@smithy/util-utf8";
-import { Sha256 } from "@aws-crypto/sha256-js";
-
-import {
- BaseBedrockInput,
- BedrockLLMInputOutputAdapter,
- type CredentialType,
-} from "../../util/bedrock.js";
-import { getEnvironmentVariable } from "../../util/env.js";
-import { SimpleChatModel, BaseChatModelParams } from "../base.js";
-import { CallbackManagerForLLMRun } from "../../callbacks/manager.js";
-import {
- AIMessageChunk,
- BaseMessage,
- AIMessage,
- ChatGenerationChunk,
- ChatMessage,
-} from "../../schema/index.js";
-import type { SerializedFields } from "../../load/map_keys.js";
-
-function convertOneMessageToText(
- message: BaseMessage,
- humanPrompt: string,
- aiPrompt: string
-): string {
- if (message._getType() === "human") {
- return `${humanPrompt} ${message.content}`;
- } else if (message._getType() === "ai") {
- return `${aiPrompt} ${message.content}`;
- } else if (message._getType() === "system") {
- return `${humanPrompt} ${message.content}`;
- } else if (ChatMessage.isInstance(message)) {
- return `\n\n${
- message.role[0].toUpperCase() + message.role.slice(1)
- }: {message.content}`;
- }
- throw new Error(`Unknown role: ${message._getType()}`);
-}
-
-export function convertMessagesToPromptAnthropic(
- messages: BaseMessage[],
- humanPrompt = "\n\nHuman:",
- aiPrompt = "\n\nAssistant:"
-): string {
- const messagesCopy = [...messages];
-
- if (
- messagesCopy.length === 0 ||
- messagesCopy[messagesCopy.length - 1]._getType() !== "ai"
- ) {
- messagesCopy.push(new AIMessage({ content: "" }));
- }
-
- return messagesCopy
- .map((message) => convertOneMessageToText(message, humanPrompt, aiPrompt))
- .join("");
-}
-
-/**
- * Function that converts an array of messages into a single string prompt
- * that can be used as input for a chat model. It delegates the conversion
- * logic to the appropriate provider-specific function.
- * @param messages Array of messages to be converted.
- * @param options Options to be used during the conversion.
- * @returns A string prompt that can be used as input for a chat model.
- */
-export function convertMessagesToPrompt(
- messages: BaseMessage[],
- provider: string
-): string {
- if (provider === "anthropic") {
- return convertMessagesToPromptAnthropic(messages);
- }
- throw new Error(`Provider ${provider} does not support chat.`);
-}
-
-/**
- * A type of Large Language Model (LLM) that interacts with the Bedrock
- * service. It extends the base `LLM` class and implements the
- * `BaseBedrockInput` interface. The class is designed to authenticate and
- * interact with the Bedrock service, which is a part of Amazon Web
- * Services (AWS). It uses AWS credentials for authentication and can be
- * configured with various parameters such as the model to use, the AWS
- * region, and the maximum number of tokens to generate.
- * @example
- * ```typescript
- * const model = new BedrockChat({
- * model: "anthropic.claude-v2",
- * region: "us-east-1",
- * });
- * const res = await model.invoke([{ content: "Tell me a joke" }]);
- * console.log(res);
- * ```
- */
-export class BedrockChat extends SimpleChatModel implements BaseBedrockInput {
- model = "amazon.titan-tg1-large";
-
- region: string;
-
- credentials: CredentialType;
-
- temperature?: number | undefined = undefined;
-
- maxTokens?: number | undefined = undefined;
-
- fetchFn: typeof fetch;
-
- endpointHost?: string;
-
- /** @deprecated */
- stopSequences?: string[];
-
- modelKwargs?: Record;
-
- codec: EventStreamCodec = new EventStreamCodec(toUtf8, fromUtf8);
-
- streaming = false;
-
- lc_serializable = true;
-
- get lc_aliases(): Record {
- return {
- model: "model_id",
- region: "region_name",
- };
- }
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- "credentials.accessKeyId": "BEDROCK_AWS_ACCESS_KEY_ID",
- "credentials.secretAccessKey": "BEDROCK_AWS_SECRET_ACCESS_KEY",
- };
- }
-
- get lc_attributes(): SerializedFields | undefined {
- return { region: this.region };
- }
-
- _llmType() {
- return "bedrock";
- }
-
- static lc_name() {
- return "BedrockChat";
- }
-
- constructor(fields?: Partial & BaseChatModelParams) {
- super(fields ?? {});
-
- this.model = fields?.model ?? this.model;
- const allowedModels = ["ai21", "anthropic", "amazon", "cohere", "meta"];
- if (!allowedModels.includes(this.model.split(".")[0])) {
- throw new Error(
- `Unknown model: '${this.model}', only these are supported: ${allowedModels}`
- );
- }
- const region =
- fields?.region ?? getEnvironmentVariable("AWS_DEFAULT_REGION");
- if (!region) {
- throw new Error(
- "Please set the AWS_DEFAULT_REGION environment variable or pass it to the constructor as the region field."
- );
- }
- this.region = region;
-
- const credentials = fields?.credentials;
- if (!credentials) {
- throw new Error(
- "Please set the AWS credentials in the 'credentials' field."
- );
- }
- this.credentials = credentials;
-
- this.temperature = fields?.temperature ?? this.temperature;
- this.maxTokens = fields?.maxTokens ?? this.maxTokens;
- this.fetchFn = fields?.fetchFn ?? fetch.bind(globalThis);
- this.endpointHost = fields?.endpointHost ?? fields?.endpointUrl;
- this.stopSequences = fields?.stopSequences;
- this.modelKwargs = fields?.modelKwargs;
- this.streaming = fields?.streaming ?? this.streaming;
- }
-
- /** Call out to Bedrock service model.
- Arguments:
- prompt: The prompt to pass into the model.
-
- Returns:
- The string generated by the model.
-
- Example:
- response = model.call("Tell me a joke.")
- */
- async _call(
- messages: BaseMessage[],
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): Promise {
- const service = "bedrock-runtime";
- const endpointHost =
- this.endpointHost ?? `${service}.${this.region}.amazonaws.com`;
- const provider = this.model.split(".")[0];
- if (this.streaming) {
- const stream = this._streamResponseChunks(messages, options, runManager);
- let finalResult: ChatGenerationChunk | undefined;
- for await (const chunk of stream) {
- if (finalResult === undefined) {
- finalResult = chunk;
- } else {
- finalResult = finalResult.concat(chunk);
- }
- }
- const messageContent = finalResult?.message.content;
- if (messageContent && typeof messageContent !== "string") {
- throw new Error(
- "Non-string output for ChatBedrock is currently not supported."
- );
- }
- return messageContent ?? "";
- }
-
- const response = await this._signedFetch(messages, options, {
- bedrockMethod: "invoke",
- endpointHost,
- provider,
- });
- const json = await response.json();
- if (!response.ok) {
- throw new Error(
- `Error ${response.status}: ${json.message ?? JSON.stringify(json)}`
- );
- }
- const text = BedrockLLMInputOutputAdapter.prepareOutput(provider, json);
- return text;
- }
-
- async _signedFetch(
- messages: BaseMessage[],
- options: this["ParsedCallOptions"],
- fields: {
- bedrockMethod: "invoke" | "invoke-with-response-stream";
- endpointHost: string;
- provider: string;
- }
- ) {
- const { bedrockMethod, endpointHost, provider } = fields;
- const inputBody = BedrockLLMInputOutputAdapter.prepareInput(
- provider,
- convertMessagesToPromptAnthropic(messages),
- this.maxTokens,
- this.temperature,
- options.stop ?? this.stopSequences,
- this.modelKwargs,
- fields.bedrockMethod
- );
-
- const url = new URL(
- `https://${endpointHost}/model/${this.model}/${bedrockMethod}`
- );
-
- const request = new HttpRequest({
- hostname: url.hostname,
- path: url.pathname,
- protocol: url.protocol,
- method: "POST", // method must be uppercase
- body: JSON.stringify(inputBody),
- query: Object.fromEntries(url.searchParams.entries()),
- headers: {
- // host is required by AWS Signature V4: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
- host: url.host,
- accept: "application/json",
- "content-type": "application/json",
- },
- });
-
- const signer = new SignatureV4({
- credentials: this.credentials,
- service: "bedrock",
- region: this.region,
- sha256: Sha256,
- });
-
- const signedRequest = await signer.sign(request);
-
- // Send request to AWS using the low-level fetch API
- const response = await this.caller.callWithOptions(
- { signal: options.signal },
- async () =>
- this.fetchFn(url, {
- headers: signedRequest.headers,
- body: signedRequest.body,
- method: signedRequest.method,
- })
- );
- return response;
- }
-
- async *_streamResponseChunks(
- messages: BaseMessage[],
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): AsyncGenerator {
- const provider = this.model.split(".")[0];
- const service = "bedrock-runtime";
-
- const endpointHost =
- this.endpointHost ?? `${service}.${this.region}.amazonaws.com`;
-
- const bedrockMethod =
- provider === "anthropic" || provider === "cohere" || provider === "meta"
- ? "invoke-with-response-stream"
- : "invoke";
-
- const response = await this._signedFetch(messages, options, {
- bedrockMethod,
- endpointHost,
- provider,
- });
-
- if (response.status < 200 || response.status >= 300) {
- throw Error(
- `Failed to access underlying url '${endpointHost}': got ${
- response.status
- } ${response.statusText}: ${await response.text()}`
- );
- }
-
- if (
- provider === "anthropic" ||
- provider === "cohere" ||
- provider === "meta"
- ) {
- const reader = response.body?.getReader();
- const decoder = new TextDecoder();
- for await (const chunk of this._readChunks(reader)) {
- const event = this.codec.decode(chunk);
- if (
- (event.headers[":event-type"] !== undefined &&
- event.headers[":event-type"].value !== "chunk") ||
- event.headers[":content-type"].value !== "application/json"
- ) {
- throw Error(`Failed to get event chunk: got ${chunk}`);
- }
- const body = JSON.parse(decoder.decode(event.body));
- if (body.message) {
- throw new Error(body.message);
- }
- if (body.bytes !== undefined) {
- const chunkResult = JSON.parse(
- decoder.decode(
- Uint8Array.from(atob(body.bytes), (m) => m.codePointAt(0) ?? 0)
- )
- );
- const text = BedrockLLMInputOutputAdapter.prepareOutput(
- provider,
- chunkResult
- );
- yield new ChatGenerationChunk({
- text,
- message: new AIMessageChunk({ content: text }),
- });
- // eslint-disable-next-line no-void
- void runManager?.handleLLMNewToken(text);
- }
- }
- } else {
- const json = await response.json();
- const text = BedrockLLMInputOutputAdapter.prepareOutput(provider, json);
- yield new ChatGenerationChunk({
- text,
- message: new AIMessageChunk({ content: text }),
- });
- // eslint-disable-next-line no-void
- void runManager?.handleLLMNewToken(text);
- }
- }
-
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- _readChunks(reader: any) {
- function _concatChunks(a: Uint8Array, b: Uint8Array) {
- const newBuffer = new Uint8Array(a.length + b.length);
- newBuffer.set(a);
- newBuffer.set(b, a.length);
- return newBuffer;
- }
-
- function getMessageLength(buffer: Uint8Array) {
- if (buffer.byteLength === 0) return 0;
- const view = new DataView(
- buffer.buffer,
- buffer.byteOffset,
- buffer.byteLength
- );
-
- return view.getUint32(0, false);
- }
-
- return {
- async *[Symbol.asyncIterator]() {
- let readResult = await reader.read();
-
- let buffer: Uint8Array = new Uint8Array(0);
- while (!readResult.done) {
- const chunk: Uint8Array = readResult.value;
-
- buffer = _concatChunks(buffer, chunk);
- let messageLength = getMessageLength(buffer);
-
- while (buffer.byteLength > 0 && buffer.byteLength >= messageLength) {
- yield buffer.slice(0, messageLength);
- buffer = buffer.slice(messageLength);
- messageLength = getMessageLength(buffer);
- }
-
- readResult = await reader.read();
- }
- },
- };
- }
-
- _combineLLMOutput() {
- return {};
- }
-}
-
-/**
- * @deprecated Use `BedrockChat` instead.
- */
-export const ChatBedrock = BedrockChat;
+export * from "@langchain/community/chat_models/bedrock/web";
diff --git a/langchain/src/chat_models/cloudflare_workersai.ts b/langchain/src/chat_models/cloudflare_workersai.ts
index b8d2f5971814..009e5183f0a0 100644
--- a/langchain/src/chat_models/cloudflare_workersai.ts
+++ b/langchain/src/chat_models/cloudflare_workersai.ts
@@ -1,247 +1 @@
-import { SimpleChatModel, BaseChatModelParams } from "./base.js";
-import { BaseLanguageModelCallOptions } from "../base_language/index.js";
-import {
- AIMessageChunk,
- BaseMessage,
- ChatGenerationChunk,
- ChatMessage,
-} from "../schema/index.js";
-import { getEnvironmentVariable } from "../util/env.js";
-import { CloudflareWorkersAIInput } from "../llms/cloudflare_workersai.js";
-import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import { convertEventStreamToIterableReadableDataStream } from "../util/event-source-parse.js";
-
-/**
- * An interface defining the options for a Cloudflare Workers AI call. It extends
- * the BaseLanguageModelCallOptions interface.
- */
-export interface ChatCloudflareWorkersAICallOptions
- extends BaseLanguageModelCallOptions {}
-
-/**
- * A class that enables calls to the Cloudflare Workers AI API to access large language
- * models in a chat-like fashion. It extends the SimpleChatModel class and
- * implements the CloudflareWorkersAIInput interface.
- * @example
- * ```typescript
- * const model = new ChatCloudflareWorkersAI({
- * model: "@cf/meta/llama-2-7b-chat-int8",
- * cloudflareAccountId: process.env.CLOUDFLARE_ACCOUNT_ID,
- * cloudflareApiToken: process.env.CLOUDFLARE_API_TOKEN
- * });
- *
- * const response = await model.invoke([
- * ["system", "You are a helpful assistant that translates English to German."],
- * ["human", `Translate "I love programming".`]
- * ]);
- *
- * console.log(response);
- * ```
- */
-export class ChatCloudflareWorkersAI
- extends SimpleChatModel
- implements CloudflareWorkersAIInput
-{
- static lc_name() {
- return "ChatCloudflareWorkersAI";
- }
-
- lc_serializable = true;
-
- model = "@cf/meta/llama-2-7b-chat-int8";
-
- cloudflareAccountId?: string;
-
- cloudflareApiToken?: string;
-
- baseUrl: string;
-
- streaming = false;
-
- constructor(fields?: CloudflareWorkersAIInput & BaseChatModelParams) {
- super(fields ?? {});
-
- this.model = fields?.model ?? this.model;
- this.streaming = fields?.streaming ?? this.streaming;
- this.cloudflareAccountId =
- fields?.cloudflareAccountId ??
- getEnvironmentVariable("CLOUDFLARE_ACCOUNT_ID");
- this.cloudflareApiToken =
- fields?.cloudflareApiToken ??
- getEnvironmentVariable("CLOUDFLARE_API_TOKEN");
- this.baseUrl =
- fields?.baseUrl ??
- `https://api.cloudflare.com/client/v4/accounts/${this.cloudflareAccountId}/ai/run`;
- if (this.baseUrl.endsWith("/")) {
- this.baseUrl = this.baseUrl.slice(0, -1);
- }
- }
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- cloudflareApiToken: "CLOUDFLARE_API_TOKEN",
- };
- }
-
- _llmType() {
- return "cloudflare";
- }
-
- /** Get the identifying parameters for this LLM. */
- get identifyingParams() {
- return { model: this.model };
- }
-
- /**
- * Get the parameters used to invoke the model
- */
- invocationParams(_options?: this["ParsedCallOptions"]) {
- return {
- model: this.model,
- };
- }
-
- _combineLLMOutput() {
- return {};
- }
-
- /**
- * Method to validate the environment.
- */
- validateEnvironment() {
- if (!this.cloudflareAccountId) {
- throw new Error(
- `No Cloudflare account ID found. Please provide it when instantiating the CloudflareWorkersAI class, or set it as "CLOUDFLARE_ACCOUNT_ID" in your environment variables.`
- );
- }
- if (!this.cloudflareApiToken) {
- throw new Error(
- `No Cloudflare API key found. Please provide it when instantiating the CloudflareWorkersAI class, or set it as "CLOUDFLARE_API_KEY" in your environment variables.`
- );
- }
- }
-
- async _request(
- messages: BaseMessage[],
- options: this["ParsedCallOptions"],
- stream?: boolean
- ) {
- this.validateEnvironment();
- const url = `${this.baseUrl}/${this.model}`;
- const headers = {
- Authorization: `Bearer ${this.cloudflareApiToken}`,
- "Content-Type": "application/json",
- };
-
- const formattedMessages = this._formatMessages(messages);
-
- const data = { messages: formattedMessages, stream };
- return this.caller.call(async () => {
- const response = await fetch(url, {
- method: "POST",
- headers,
- body: JSON.stringify(data),
- signal: options.signal,
- });
- if (!response.ok) {
- const error = new Error(
- `Cloudflare LLM call failed with status code ${response.status}`
- );
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- (error as any).response = response;
- throw error;
- }
- return response;
- });
- }
-
- async *_streamResponseChunks(
- messages: BaseMessage[],
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): AsyncGenerator {
- const response = await this._request(messages, options, true);
- if (!response.body) {
- throw new Error("Empty response from Cloudflare. Please try again.");
- }
- const stream = convertEventStreamToIterableReadableDataStream(
- response.body
- );
- for await (const chunk of stream) {
- if (chunk !== "[DONE]") {
- const parsedChunk = JSON.parse(chunk);
- const generationChunk = new ChatGenerationChunk({
- message: new AIMessageChunk({ content: parsedChunk.response }),
- text: parsedChunk.response,
- });
- yield generationChunk;
- // eslint-disable-next-line no-void
- void runManager?.handleLLMNewToken(generationChunk.text ?? "");
- }
- }
- }
-
- protected _formatMessages(
- messages: BaseMessage[]
- ): { role: string; content: string }[] {
- const formattedMessages = messages.map((message) => {
- let role;
- if (message._getType() === "human") {
- role = "user";
- } else if (message._getType() === "ai") {
- role = "assistant";
- } else if (message._getType() === "system") {
- role = "system";
- } else if (ChatMessage.isInstance(message)) {
- role = message.role;
- } else {
- console.warn(
- `Unsupported message type passed to Cloudflare: "${message._getType()}"`
- );
- role = "user";
- }
- if (typeof message.content !== "string") {
- throw new Error(
- "ChatCloudflareWorkersAI currently does not support non-string message content."
- );
- }
- return {
- role,
- content: message.content,
- };
- });
- return formattedMessages;
- }
-
- /** @ignore */
- async _call(
- messages: BaseMessage[],
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): Promise {
- if (!this.streaming) {
- const response = await this._request(messages, options);
-
- const responseData = await response.json();
-
- return responseData.result.response;
- } else {
- const stream = this._streamResponseChunks(messages, options, runManager);
- let finalResult: ChatGenerationChunk | undefined;
- for await (const chunk of stream) {
- if (finalResult === undefined) {
- finalResult = chunk;
- } else {
- finalResult = finalResult.concat(chunk);
- }
- }
- const messageContent = finalResult?.message.content;
- if (messageContent && typeof messageContent !== "string") {
- throw new Error(
- "Non-string output for ChatCloudflareWorkersAI is currently not supported."
- );
- }
- return messageContent ?? "";
- }
- }
-}
+export * from "@langchain/community/chat_models/cloudflare_workersai";
diff --git a/langchain/src/chat_models/fireworks.ts b/langchain/src/chat_models/fireworks.ts
index 29e12cc34ea2..438f96c7c33d 100644
--- a/langchain/src/chat_models/fireworks.ts
+++ b/langchain/src/chat_models/fireworks.ts
@@ -1,137 +1 @@
-import type { OpenAI as OpenAIClient } from "openai";
-import type { ChatOpenAICallOptions, OpenAIChatInput } from "./openai.js";
-import type { OpenAICoreRequestOptions } from "../types/openai-types.js";
-import type { BaseChatModelParams } from "./base.js";
-import { ChatOpenAI } from "./openai.js";
-import { getEnvironmentVariable } from "../util/env.js";
-
-type FireworksUnsupportedArgs =
- | "frequencyPenalty"
- | "presencePenalty"
- | "logitBias"
- | "functions";
-
-type FireworksUnsupportedCallOptions = "functions" | "function_call" | "tools";
-
-export type ChatFireworksCallOptions = Partial<
- Omit
->;
-
-/**
- * Wrapper around Fireworks API for large language models fine-tuned for chat
- *
- * Fireworks API is compatible to the OpenAI API with some limitations described in
- * https://readme.fireworks.ai/docs/openai-compatibility.
- *
- * To use, you should have the `openai` package installed and
- * the `FIREWORKS_API_KEY` environment variable set.
- * @example
- * ```typescript
- * const model = new ChatFireworks({
- * temperature: 0.9,
- * fireworksApiKey: "YOUR-API-KEY",
- * });
- *
- * const response = await model.invoke("Hello, how are you?");
- * console.log(response);
- * ```
- */
-export class ChatFireworks extends ChatOpenAI {
- static lc_name() {
- return "ChatFireworks";
- }
-
- _llmType() {
- return "fireworks";
- }
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- fireworksApiKey: "FIREWORKS_API_KEY",
- };
- }
-
- lc_serializable = true;
-
- fireworksApiKey?: string;
-
- constructor(
- fields?: Partial<
- Omit
- > &
- BaseChatModelParams & { fireworksApiKey?: string }
- ) {
- const fireworksApiKey =
- fields?.fireworksApiKey || getEnvironmentVariable("FIREWORKS_API_KEY");
-
- if (!fireworksApiKey) {
- throw new Error(
- `Fireworks API key not found. Please set the FIREWORKS_API_KEY environment variable or provide the key into "fireworksApiKey"`
- );
- }
-
- super({
- ...fields,
- modelName:
- fields?.modelName || "accounts/fireworks/models/llama-v2-13b-chat",
- openAIApiKey: fireworksApiKey,
- configuration: {
- baseURL: "https://api.fireworks.ai/inference/v1",
- },
- });
-
- this.fireworksApiKey = fireworksApiKey;
- }
-
- toJSON() {
- const result = super.toJSON();
-
- if (
- "kwargs" in result &&
- typeof result.kwargs === "object" &&
- result.kwargs != null
- ) {
- delete result.kwargs.openai_api_key;
- delete result.kwargs.configuration;
- }
-
- return result;
- }
-
- async completionWithRetry(
- request: OpenAIClient.Chat.ChatCompletionCreateParamsStreaming,
- options?: OpenAICoreRequestOptions
- ): Promise>;
-
- async completionWithRetry(
- request: OpenAIClient.Chat.ChatCompletionCreateParamsNonStreaming,
- options?: OpenAICoreRequestOptions
- ): Promise;
-
- /**
- * Calls the Fireworks API with retry logic in case of failures.
- * @param request The request to send to the Fireworks API.
- * @param options Optional configuration for the API call.
- * @returns The response from the Fireworks API.
- */
- async completionWithRetry(
- request:
- | OpenAIClient.Chat.ChatCompletionCreateParamsStreaming
- | OpenAIClient.Chat.ChatCompletionCreateParamsNonStreaming,
- options?: OpenAICoreRequestOptions
- ): Promise<
- | AsyncIterable
- | OpenAIClient.Chat.Completions.ChatCompletion
- > {
- delete request.frequency_penalty;
- delete request.presence_penalty;
- delete request.logit_bias;
- delete request.functions;
-
- if (request.stream === true) {
- return super.completionWithRetry(request, options);
- }
-
- return super.completionWithRetry(request, options);
- }
-}
+export * from "@langchain/community/chat_models/fireworks";
diff --git a/langchain/src/chat_models/googlepalm.ts b/langchain/src/chat_models/googlepalm.ts
index 56cca1023943..53f338a9674d 100644
--- a/langchain/src/chat_models/googlepalm.ts
+++ b/langchain/src/chat_models/googlepalm.ts
@@ -1,340 +1 @@
-import { DiscussServiceClient } from "@google-ai/generativelanguage";
-import type { protos } from "@google-ai/generativelanguage";
-import { GoogleAuth } from "google-auth-library";
-import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import {
- AIMessage,
- BaseMessage,
- ChatMessage,
- ChatResult,
- isBaseMessage,
-} from "../schema/index.js";
-import { getEnvironmentVariable } from "../util/env.js";
-import { BaseChatModel, BaseChatModelParams } from "./base.js";
-
-export type BaseMessageExamplePair = {
- input: BaseMessage;
- output: BaseMessage;
-};
-
-/**
- * An interface defining the input to the ChatGooglePaLM class.
- */
-export interface GooglePaLMChatInput extends BaseChatModelParams {
- /**
- * Model Name to use
- *
- * Note: The format must follow the pattern - `models/{model}`
- */
- modelName?: string;
-
- /**
- * Controls the randomness of the output.
- *
- * Values can range from [0.0,1.0], inclusive. A value closer to 1.0
- * will produce responses that are more varied and creative, while
- * a value closer to 0.0 will typically result in less surprising
- * responses from the model.
- *
- * Note: The default value varies by model
- */
- temperature?: number;
-
- /**
- * Top-p changes how the model selects tokens for output.
- *
- * Tokens are selected from most probable to least until the sum
- * of their probabilities equals the top-p value.
- *
- * For example, if tokens A, B, and C have a probability of
- * .3, .2, and .1 and the top-p value is .5, then the model will
- * select either A or B as the next token (using temperature).
- *
- * Note: The default value varies by model
- */
- topP?: number;
-
- /**
- * Top-k changes how the model selects tokens for output.
- *
- * A top-k of 1 means the selected token is the most probable among
- * all tokens in the model’s vocabulary (also called greedy decoding),
- * while a top-k of 3 means that the next token is selected from
- * among the 3 most probable tokens (using temperature).
- *
- * Note: The default value varies by model
- */
- topK?: number;
-
- examples?:
- | protos.google.ai.generativelanguage.v1beta2.IExample[]
- | BaseMessageExamplePair[];
-
- /**
- * Google Palm API key to use
- */
- apiKey?: string;
-}
-
-function getMessageAuthor(message: BaseMessage) {
- const type = message._getType();
- if (ChatMessage.isInstance(message)) {
- return message.role;
- }
- return message.name ?? type;
-}
-
-/**
- * A class that wraps the Google Palm chat model.
- * @example
- * ```typescript
- * const model = new ChatGooglePaLM({
- * apiKey: "",
- * temperature: 0.7,
- * modelName: "models/chat-bison-001",
- * topK: 40,
- * topP: 1,
- * examples: [
- * {
- * input: new HumanMessage("What is your favorite sock color?"),
- * output: new AIMessage("My favorite sock color be arrrr-ange!"),
- * },
- * ],
- * });
- * const questions = [
- * new SystemMessage(
- * "You are a funny assistant that answers in pirate language."
- * ),
- * new HumanMessage("What is your favorite food?"),
- * ];
- * const res = await model.call(questions);
- * console.log({ res });
- * ```
- */
-export class ChatGooglePaLM
- extends BaseChatModel
- implements GooglePaLMChatInput
-{
- static lc_name() {
- return "ChatGooglePaLM";
- }
-
- lc_serializable = true;
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- apiKey: "GOOGLE_PALM_API_KEY",
- };
- }
-
- modelName = "models/chat-bison-001";
-
- temperature?: number; // default value chosen based on model
-
- topP?: number; // default value chosen based on model
-
- topK?: number; // default value chosen based on model
-
- examples: protos.google.ai.generativelanguage.v1beta2.IExample[] = [];
-
- apiKey?: string;
-
- private client: DiscussServiceClient;
-
- constructor(fields?: GooglePaLMChatInput) {
- super(fields ?? {});
-
- this.modelName = fields?.modelName ?? this.modelName;
-
- this.temperature = fields?.temperature ?? this.temperature;
- if (this.temperature && (this.temperature < 0 || this.temperature > 1)) {
- throw new Error("`temperature` must be in the range of [0.0,1.0]");
- }
-
- this.topP = fields?.topP ?? this.topP;
- if (this.topP && this.topP < 0) {
- throw new Error("`topP` must be a positive integer");
- }
-
- this.topK = fields?.topK ?? this.topK;
- if (this.topK && this.topK < 0) {
- throw new Error("`topK` must be a positive integer");
- }
-
- this.examples =
- fields?.examples?.map((example) => {
- if (
- (isBaseMessage(example.input) &&
- typeof example.input.content !== "string") ||
- (isBaseMessage(example.output) &&
- typeof example.output.content !== "string")
- ) {
- throw new Error(
- "GooglePaLM example messages may only have string content."
- );
- }
- return {
- input: {
- ...example.input,
- content: example.input?.content as string,
- },
- output: {
- ...example.output,
- content: example.output?.content as string,
- },
- };
- }) ?? this.examples;
-
- this.apiKey =
- fields?.apiKey ?? getEnvironmentVariable("GOOGLE_PALM_API_KEY");
- if (!this.apiKey) {
- throw new Error(
- "Please set an API key for Google Palm 2 in the environment variable GOOGLE_PALM_API_KEY or in the `apiKey` field of the GooglePalm constructor"
- );
- }
-
- this.client = new DiscussServiceClient({
- authClient: new GoogleAuth().fromAPIKey(this.apiKey),
- });
- }
-
- _combineLLMOutput() {
- return [];
- }
-
- _llmType() {
- return "googlepalm";
- }
-
- async _generate(
- messages: BaseMessage[],
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): Promise {
- const palmMessages = await this.caller.callWithOptions(
- { signal: options.signal },
- this._generateMessage.bind(this),
- this._mapBaseMessagesToPalmMessages(messages),
- this._getPalmContextInstruction(messages),
- this.examples
- );
- const chatResult = this._mapPalmMessagesToChatResult(palmMessages);
-
- // Google Palm doesn't provide streaming as of now. But to support streaming handlers
- // we call the handler with entire response text
- void runManager?.handleLLMNewToken(
- chatResult.generations.length > 0 ? chatResult.generations[0].text : ""
- );
-
- return chatResult;
- }
-
- protected async _generateMessage(
- messages: protos.google.ai.generativelanguage.v1beta2.IMessage[],
- context?: string,
- examples?: protos.google.ai.generativelanguage.v1beta2.IExample[]
- ): Promise {
- const [palmMessages] = await this.client.generateMessage({
- candidateCount: 1,
- model: this.modelName,
- temperature: this.temperature,
- topK: this.topK,
- topP: this.topP,
- prompt: {
- context,
- examples,
- messages,
- },
- });
- return palmMessages;
- }
-
- protected _getPalmContextInstruction(
- messages: BaseMessage[]
- ): string | undefined {
- // get the first message and checks if it's a system 'system' messages
- const systemMessage =
- messages.length > 0 && getMessageAuthor(messages[0]) === "system"
- ? messages[0]
- : undefined;
- if (
- systemMessage?.content !== undefined &&
- typeof systemMessage.content !== "string"
- ) {
- throw new Error("Non-string system message content is not supported.");
- }
- return systemMessage?.content;
- }
-
- protected _mapBaseMessagesToPalmMessages(
- messages: BaseMessage[]
- ): protos.google.ai.generativelanguage.v1beta2.IMessage[] {
- // remove all 'system' messages
- const nonSystemMessages = messages.filter(
- (m) => getMessageAuthor(m) !== "system"
- );
-
- // requires alternate human & ai messages. Throw error if two messages are consecutive
- nonSystemMessages.forEach((msg, index) => {
- if (index < 1) return;
- if (
- getMessageAuthor(msg) === getMessageAuthor(nonSystemMessages[index - 1])
- ) {
- throw new Error(
- `Google PaLM requires alternate messages between authors`
- );
- }
- });
-
- return nonSystemMessages.map((m) => {
- if (typeof m.content !== "string") {
- throw new Error(
- "ChatGooglePaLM does not support non-string message content."
- );
- }
- return {
- author: getMessageAuthor(m),
- content: m.content,
- citationMetadata: {
- citationSources: m.additional_kwargs.citationSources as
- | protos.google.ai.generativelanguage.v1beta2.ICitationSource[]
- | undefined,
- },
- };
- });
- }
-
- protected _mapPalmMessagesToChatResult(
- msgRes: protos.google.ai.generativelanguage.v1beta2.IGenerateMessageResponse
- ): ChatResult {
- if (
- msgRes.candidates &&
- msgRes.candidates.length > 0 &&
- msgRes.candidates[0]
- ) {
- const message = msgRes.candidates[0];
- return {
- generations: [
- {
- text: message.content ?? "",
- message: new AIMessage({
- content: message.content ?? "",
- name: message.author === null ? undefined : message.author,
- additional_kwargs: {
- citationSources: message.citationMetadata?.citationSources,
- filters: msgRes.filters, // content filters applied
- },
- }),
- },
- ],
- };
- }
- // if rejected or error, return empty generations with reason in filters
- return {
- generations: [],
- llmOutput: {
- filters: msgRes.filters,
- },
- };
- }
-}
+export * from "@langchain/community/chat_models/googlepalm";
diff --git a/langchain/src/chat_models/googlevertexai/index.ts b/langchain/src/chat_models/googlevertexai/index.ts
index e8a3a07da320..b2977f65c20a 100644
--- a/langchain/src/chat_models/googlevertexai/index.ts
+++ b/langchain/src/chat_models/googlevertexai/index.ts
@@ -1,64 +1 @@
-import { GoogleAuthOptions } from "google-auth-library";
-import { BaseChatGoogleVertexAI, GoogleVertexAIChatInput } from "./common.js";
-import { GoogleVertexAILLMConnection } from "../../util/googlevertexai-connection.js";
-import { GAuthClient } from "../../util/googlevertexai-gauth.js";
-
-/**
- * Enables calls to the Google Cloud's Vertex AI API to access
- * Large Language Models in a chat-like fashion.
- *
- * To use, you will need to have one of the following authentication
- * methods in place:
- * - You are logged into an account permitted to the Google Cloud project
- * using Vertex AI.
- * - You are running this on a machine using a service account permitted to
- * the Google Cloud project using Vertex AI.
- * - The `GOOGLE_APPLICATION_CREDENTIALS` environment variable is set to the
- * path of a credentials file for a service account permitted to the
- * Google Cloud project using Vertex AI.
- * @example
- * ```typescript
- * const model = new ChatGoogleVertexAI({
- * temperature: 0.7,
- * });
- * const result = await model.invoke("What is the capital of France?");
- * ```
- */
-export class ChatGoogleVertexAI extends BaseChatGoogleVertexAI {
- static lc_name() {
- return "ChatVertexAI";
- }
-
- constructor(fields?: GoogleVertexAIChatInput) {
- super(fields);
-
- const client = new GAuthClient({
- scopes: "https://www.googleapis.com/auth/cloud-platform",
- ...fields?.authOptions,
- });
-
- this.connection = new GoogleVertexAILLMConnection(
- { ...fields, ...this },
- this.caller,
- client,
- false
- );
-
- this.streamedConnection = new GoogleVertexAILLMConnection(
- { ...fields, ...this },
- this.caller,
- client,
- true
- );
- }
-}
-
-export type {
- ChatExample,
- GoogleVertexAIChatAuthor,
- GoogleVertexAIChatInput,
- GoogleVertexAIChatInstance,
- GoogleVertexAIChatMessage,
- GoogleVertexAIChatMessageFields,
- GoogleVertexAIChatPrediction,
-} from "./common.js";
+export * from "@langchain/community/chat_models/googlevertexai";
diff --git a/langchain/src/chat_models/googlevertexai/web.ts b/langchain/src/chat_models/googlevertexai/web.ts
index acbaa9144f4c..4c350a89266a 100644
--- a/langchain/src/chat_models/googlevertexai/web.ts
+++ b/langchain/src/chat_models/googlevertexai/web.ts
@@ -1,66 +1 @@
-import { GoogleVertexAILLMConnection } from "../../util/googlevertexai-connection.js";
-import {
- WebGoogleAuthOptions,
- WebGoogleAuth,
-} from "../../util/googlevertexai-webauth.js";
-import { BaseChatGoogleVertexAI, GoogleVertexAIChatInput } from "./common.js";
-
-/**
- * Enables calls to the Google Cloud's Vertex AI API to access
- * Large Language Models in a chat-like fashion.
- *
- * This entrypoint and class are intended to be used in web environments like Edge
- * functions where you do not have access to the file system. It supports passing
- * service account credentials directly as a "GOOGLE_VERTEX_AI_WEB_CREDENTIALS"
- * environment variable or directly as "authOptions.credentials".
- * @example
- * ```typescript
- * const model = new ChatGoogleVertexAI({
- * temperature: 0.7,
- * });
- * const result = await model.invoke(
- * "How do I implement a binary search algorithm in Python?",
- * );
- * ```
- */
-export class ChatGoogleVertexAI extends BaseChatGoogleVertexAI {
- static lc_name() {
- return "ChatVertexAI";
- }
-
- get lc_secrets(): { [key: string]: string } {
- return {
- "authOptions.credentials": "GOOGLE_VERTEX_AI_WEB_CREDENTIALS",
- };
- }
-
- constructor(fields?: GoogleVertexAIChatInput) {
- super(fields);
-
- const client = new WebGoogleAuth(fields?.authOptions);
-
- this.connection = new GoogleVertexAILLMConnection(
- { ...fields, ...this },
- this.caller,
- client,
- false
- );
-
- this.streamedConnection = new GoogleVertexAILLMConnection(
- { ...fields, ...this },
- this.caller,
- client,
- true
- );
- }
-}
-
-export type {
- ChatExample,
- GoogleVertexAIChatAuthor,
- GoogleVertexAIChatInput,
- GoogleVertexAIChatInstance,
- GoogleVertexAIChatMessage,
- GoogleVertexAIChatMessageFields,
- GoogleVertexAIChatPrediction,
-} from "./common.js";
+export * from "@langchain/community/chat_models/googlevertexai/web";
diff --git a/langchain/src/chat_models/iflytek_xinghuo/index.ts b/langchain/src/chat_models/iflytek_xinghuo/index.ts
index ac54461be18a..9b988a537704 100644
--- a/langchain/src/chat_models/iflytek_xinghuo/index.ts
+++ b/langchain/src/chat_models/iflytek_xinghuo/index.ts
@@ -1,43 +1 @@
-import WebSocket from "ws";
-import { BaseChatIflytekXinghuo } from "./common.js";
-import {
- BaseWebSocketStream,
- WebSocketStreamOptions,
-} from "../../util/iflytek_websocket_stream.js";
-
-class WebSocketStream extends BaseWebSocketStream {
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- openWebSocket(url: string, options: WebSocketStreamOptions): WebSocket {
- return new WebSocket(url, options.protocols ?? []);
- }
-}
-
-/**
- * @example
- * ```typescript
- * const model = new ChatIflytekXinghuo();
- * const response = await model.call([new HumanMessage("Nice to meet you!")]);
- * console.log(response);
- * ```
- */
-export class ChatIflytekXinghuo extends BaseChatIflytekXinghuo {
- async openWebSocketStream(
- options: WebSocketStreamOptions
- ): Promise {
- const host = "spark-api.xf-yun.com";
- const date = new Date().toUTCString();
- const url = `GET /${this.version}/chat HTTP/1.1`;
- const { createHmac } = await import("node:crypto");
- const hash = createHmac("sha256", this.iflytekApiSecret)
- .update(`host: ${host}\ndate: ${date}\n${url}`)
- .digest("base64");
- const authorization_origin = `api_key="${this.iflytekApiKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${hash}"`;
- const authorization = Buffer.from(authorization_origin).toString("base64");
- let authWebSocketUrl = this.apiUrl;
- authWebSocketUrl += `?authorization=${authorization}`;
- authWebSocketUrl += `&host=${encodeURIComponent(host)}`;
- authWebSocketUrl += `&date=${encodeURIComponent(date)}`;
- return new WebSocketStream(authWebSocketUrl, options) as WebSocketStream;
- }
-}
+export * from "@langchain/community/chat_models/iflytek_xinghuo";
diff --git a/langchain/src/chat_models/iflytek_xinghuo/web.ts b/langchain/src/chat_models/iflytek_xinghuo/web.ts
index 87b372b802ad..8867445ee59c 100644
--- a/langchain/src/chat_models/iflytek_xinghuo/web.ts
+++ b/langchain/src/chat_models/iflytek_xinghuo/web.ts
@@ -1,49 +1 @@
-import { BaseChatIflytekXinghuo } from "./common.js";
-import {
- WebSocketStreamOptions,
- BaseWebSocketStream,
-} from "../../util/iflytek_websocket_stream.js";
-
-class WebSocketStream extends BaseWebSocketStream {
- openWebSocket(url: string, options: WebSocketStreamOptions): WebSocket {
- return new WebSocket(url, options.protocols ?? []);
- }
-}
-
-/**
- * @example
- * ```typescript
- * const model = new ChatIflytekXinghuo();
- * const response = await model.call([new HumanMessage("Nice to meet you!")]);
- * console.log(response);
- * ```
- */
-export class ChatIflytekXinghuo extends BaseChatIflytekXinghuo {
- async openWebSocketStream(
- options: WebSocketStreamOptions
- ): Promise {
- const host = "spark-api.xf-yun.com";
- const date = new Date().toUTCString();
- const url = `GET /${this.version}/chat HTTP/1.1`;
- const keyBuffer = new TextEncoder().encode(this.iflytekApiSecret);
- const dataBuffer = new TextEncoder().encode(
- `host: ${host}\ndate: ${date}\n${url}`
- );
- const cryptoKey = await crypto.subtle.importKey(
- "raw",
- keyBuffer,
- { name: "HMAC", hash: "SHA-256" },
- false,
- ["sign"]
- );
- const signature = await crypto.subtle.sign("HMAC", cryptoKey, dataBuffer);
- const hash = window.btoa(String.fromCharCode(...new Uint8Array(signature)));
- const authorization_origin = `api_key="${this.iflytekApiKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${hash}"`;
- const authorization = window.btoa(authorization_origin);
- let authWebSocketUrl = this.apiUrl;
- authWebSocketUrl += `?authorization=${authorization}`;
- authWebSocketUrl += `&host=${encodeURIComponent(host)}`;
- authWebSocketUrl += `&date=${encodeURIComponent(date)}`;
- return new WebSocketStream(authWebSocketUrl, options) as WebSocketStream;
- }
-}
+export * from "@langchain/community/chat_models/iflytek_xinghuo/web";
diff --git a/langchain/src/chat_models/llama_cpp.ts b/langchain/src/chat_models/llama_cpp.ts
index 3df8b0d2a3c9..ae06e6116cfc 100644
--- a/langchain/src/chat_models/llama_cpp.ts
+++ b/langchain/src/chat_models/llama_cpp.ts
@@ -1,322 +1 @@
-import {
- LlamaModel,
- LlamaContext,
- LlamaChatSession,
- type ConversationInteraction,
-} from "node-llama-cpp";
-import { SimpleChatModel, BaseChatModelParams } from "./base.js";
-import {
- LlamaBaseCppInputs,
- createLlamaModel,
- createLlamaContext,
-} from "../util/llama_cpp.js";
-import { BaseLanguageModelCallOptions } from "../base_language/index.js";
-import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import {
- BaseMessage,
- ChatGenerationChunk,
- AIMessageChunk,
- ChatMessage,
-} from "../schema/index.js";
-
-/**
- * Note that the modelPath is the only required parameter. For testing you
- * can set this in the environment variable `LLAMA_PATH`.
- */
-export interface LlamaCppInputs
- extends LlamaBaseCppInputs,
- BaseChatModelParams {}
-
-export interface LlamaCppCallOptions extends BaseLanguageModelCallOptions {
- /** The maximum number of tokens the response should contain. */
- maxTokens?: number;
- /** A function called when matching the provided token array */
- onToken?: (tokens: number[]) => void;
-}
-
-/**
- * To use this model you need to have the `node-llama-cpp` module installed.
- * This can be installed using `npm install -S node-llama-cpp` and the minimum
- * version supported in version 2.0.0.
- * This also requires that have a locally built version of Llama2 installed.
- * @example
- * ```typescript
- * // Initialize the ChatLlamaCpp model with the path to the model binary file.
- * const model = new ChatLlamaCpp({
- * modelPath: "/Replace/with/path/to/your/model/gguf-llama2-q4_0.bin",
- * temperature: 0.5,
- * });
- *
- * // Call the model with a message and await the response.
- * const response = await model.call([
- * new HumanMessage({ content: "My name is John." }),
- * ]);
- *
- * // Log the response to the console.
- * console.log({ response });
- *
- * ```
- */
-export class ChatLlamaCpp extends SimpleChatModel {
- declare CallOptions: LlamaCppCallOptions;
-
- static inputs: LlamaCppInputs;
-
- maxTokens?: number;
-
- temperature?: number;
-
- topK?: number;
-
- topP?: number;
-
- trimWhitespaceSuffix?: boolean;
-
- _model: LlamaModel;
-
- _context: LlamaContext;
-
- _session: LlamaChatSession | null;
-
- static lc_name() {
- return "ChatLlamaCpp";
- }
-
- constructor(inputs: LlamaCppInputs) {
- super(inputs);
- this.maxTokens = inputs?.maxTokens;
- this.temperature = inputs?.temperature;
- this.topK = inputs?.topK;
- this.topP = inputs?.topP;
- this.trimWhitespaceSuffix = inputs?.trimWhitespaceSuffix;
- this._model = createLlamaModel(inputs);
- this._context = createLlamaContext(this._model, inputs);
- this._session = null;
- }
-
- _llmType() {
- return "llama2_cpp";
- }
-
- /** @ignore */
- _combineLLMOutput() {
- return {};
- }
-
- invocationParams() {
- return {
- maxTokens: this.maxTokens,
- temperature: this.temperature,
- topK: this.topK,
- topP: this.topP,
- trimWhitespaceSuffix: this.trimWhitespaceSuffix,
- };
- }
-
- /** @ignore */
- async _call(
- messages: BaseMessage[],
- options: this["ParsedCallOptions"]
- ): Promise {
- let prompt = "";
-
- if (messages.length > 1) {
- // We need to build a new _session
- prompt = this._buildSession(messages);
- } else if (!this._session) {
- prompt = this._buildSession(messages);
- } else {
- if (typeof messages[0].content !== "string") {
- throw new Error(
- "ChatLlamaCpp does not support non-string message content in sessions."
- );
- }
- // If we already have a session then we should just have a single prompt
- prompt = messages[0].content;
- }
-
- try {
- const promptOptions = {
- onToken: options.onToken,
- maxTokens: this?.maxTokens,
- temperature: this?.temperature,
- topK: this?.topK,
- topP: this?.topP,
- trimWhitespaceSuffix: this?.trimWhitespaceSuffix,
- };
- // @ts-expect-error - TS2531: Object is possibly 'null'.
- const completion = await this._session.prompt(prompt, promptOptions);
- return completion;
- } catch (e) {
- throw new Error("Error getting prompt completion.");
- }
- }
-
- async *_streamResponseChunks(
- input: BaseMessage[],
- _options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): AsyncGenerator {
- const promptOptions = {
- temperature: this?.temperature,
- topK: this?.topK,
- topP: this?.topP,
- };
-
- const prompt = this._buildPrompt(input);
-
- const stream = await this.caller.call(async () =>
- this._context.evaluate(this._context.encode(prompt), promptOptions)
- );
-
- for await (const chunk of stream) {
- yield new ChatGenerationChunk({
- text: this._context.decode([chunk]),
- message: new AIMessageChunk({
- content: this._context.decode([chunk]),
- }),
- generationInfo: {},
- });
- await runManager?.handleLLMNewToken(this._context.decode([chunk]) ?? "");
- }
- }
-
- // This constructs a new session if we need to adding in any sys messages or previous chats
- protected _buildSession(messages: BaseMessage[]): string {
- let prompt = "";
- let sysMessage = "";
- let noSystemMessages: BaseMessage[] = [];
- let interactions: ConversationInteraction[] = [];
-
- // Let's see if we have a system message
- if (messages.findIndex((msg) => msg._getType() === "system") !== -1) {
- const sysMessages = messages.filter(
- (message) => message._getType() === "system"
- );
-
- const systemMessageContent = sysMessages[sysMessages.length - 1].content;
-
- if (typeof systemMessageContent !== "string") {
- throw new Error(
- "ChatLlamaCpp does not support non-string message content in sessions."
- );
- }
- // Only use the last provided system message
- sysMessage = systemMessageContent;
-
- // Now filter out the system messages
- noSystemMessages = messages.filter(
- (message) => message._getType() !== "system"
- );
- } else {
- noSystemMessages = messages;
- }
-
- // Lets see if we just have a prompt left or are their previous interactions?
- if (noSystemMessages.length > 1) {
- // Is the last message a prompt?
- if (
- noSystemMessages[noSystemMessages.length - 1]._getType() === "human"
- ) {
- const finalMessageContent =
- noSystemMessages[noSystemMessages.length - 1].content;
- if (typeof finalMessageContent !== "string") {
- throw new Error(
- "ChatLlamaCpp does not support non-string message content in sessions."
- );
- }
- prompt = finalMessageContent;
- interactions = this._convertMessagesToInteractions(
- noSystemMessages.slice(0, noSystemMessages.length - 1)
- );
- } else {
- interactions = this._convertMessagesToInteractions(noSystemMessages);
- }
- } else {
- if (typeof noSystemMessages[0].content !== "string") {
- throw new Error(
- "ChatLlamaCpp does not support non-string message content in sessions."
- );
- }
- // If there was only a single message we assume it's a prompt
- prompt = noSystemMessages[0].content;
- }
-
- // Now lets construct a session according to what we got
- if (sysMessage !== "" && interactions.length > 0) {
- this._session = new LlamaChatSession({
- context: this._context,
- conversationHistory: interactions,
- systemPrompt: sysMessage,
- });
- } else if (sysMessage !== "" && interactions.length === 0) {
- this._session = new LlamaChatSession({
- context: this._context,
- systemPrompt: sysMessage,
- });
- } else if (sysMessage === "" && interactions.length > 0) {
- this._session = new LlamaChatSession({
- context: this._context,
- conversationHistory: interactions,
- });
- } else {
- this._session = new LlamaChatSession({
- context: this._context,
- });
- }
-
- return prompt;
- }
-
- // This builds a an array of interactions
- protected _convertMessagesToInteractions(
- messages: BaseMessage[]
- ): ConversationInteraction[] {
- const result: ConversationInteraction[] = [];
-
- for (let i = 0; i < messages.length; i += 2) {
- if (i + 1 < messages.length) {
- const prompt = messages[i].content;
- const response = messages[i + 1].content;
- if (typeof prompt !== "string" || typeof response !== "string") {
- throw new Error(
- "ChatLlamaCpp does not support non-string message content."
- );
- }
- result.push({
- prompt,
- response,
- });
- }
- }
-
- return result;
- }
-
- protected _buildPrompt(input: BaseMessage[]): string {
- const prompt = input
- .map((message) => {
- let messageText;
- if (message._getType() === "human") {
- messageText = `[INST] ${message.content} [/INST]`;
- } else if (message._getType() === "ai") {
- messageText = message.content;
- } else if (message._getType() === "system") {
- messageText = `<> ${message.content} <>`;
- } else if (ChatMessage.isInstance(message)) {
- messageText = `\n\n${message.role[0].toUpperCase()}${message.role.slice(
- 1
- )}: ${message.content}`;
- } else {
- console.warn(
- `Unsupported message type passed to llama_cpp: "${message._getType()}"`
- );
- messageText = "";
- }
- return messageText;
- })
- .join("\n");
-
- return prompt;
- }
-}
+export * from "@langchain/community/chat_models/llama_cpp";
diff --git a/langchain/src/chat_models/minimax.ts b/langchain/src/chat_models/minimax.ts
index c0e521d6fec0..6cb2a1436dbd 100644
--- a/langchain/src/chat_models/minimax.ts
+++ b/langchain/src/chat_models/minimax.ts
@@ -1,880 +1 @@
-import type { OpenAI as OpenAIClient } from "openai";
-
-import { BaseChatModel, BaseChatModelParams } from "./base.js";
-import {
- AIMessage,
- BaseMessage,
- ChatGeneration,
- ChatMessage,
- ChatResult,
- HumanMessage,
-} from "../schema/index.js";
-import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import { getEnvironmentVariable } from "../util/env.js";
-import { StructuredTool } from "../tools/index.js";
-import { BaseFunctionCallOptions } from "../base_language/index.js";
-import { formatToOpenAIFunction } from "../tools/convert_to_openai.js";
-
-/**
- * Type representing the sender_type of a message in the Minimax chat model.
- */
-export type MinimaxMessageRole = "BOT" | "USER" | "FUNCTION";
-
-/**
- * Interface representing a message in the Minimax chat model.
- */
-interface MinimaxChatCompletionRequestMessage {
- sender_type: MinimaxMessageRole;
- sender_name?: string;
- text: string;
-}
-
-/**
- * Interface representing a request for a chat completion.
- */
-interface MinimaxChatCompletionRequest {
- model: string;
- messages: MinimaxChatCompletionRequestMessage[];
- stream?: boolean;
- prompt?: string;
- temperature?: number;
- top_p?: number;
- tokens_to_generate?: number;
- skip_info_mask?: boolean;
- mask_sensitive_info?: boolean;
- beam_width?: number;
- use_standard_sse?: boolean;
- role_meta?: RoleMeta;
- bot_setting?: BotSetting[];
- reply_constraints?: ReplyConstraints;
- sample_messages?: MinimaxChatCompletionRequestMessage[];
- /**
- * A list of functions the model may generate JSON inputs for.
- * @type {Array}
- */
- functions?: OpenAIClient.Chat.ChatCompletionCreateParams.Function[];
- plugins?: string[];
-}
-
-interface RoleMeta {
- role_meta: string;
- bot_name: string;
-}
-
-interface RawGlyph {
- type: "raw";
- raw_glyph: string;
-}
-
-interface JsonGlyph {
- type: "json_value";
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- json_properties: any;
-}
-
-type ReplyConstraintsGlyph = RawGlyph | JsonGlyph;
-
-interface ReplyConstraints {
- sender_type: string;
- sender_name: string;
- glyph?: ReplyConstraintsGlyph;
-}
-
-interface BotSetting {
- content: string;
- bot_name: string;
-}
-
-export declare interface ConfigurationParameters {
- basePath?: string;
- headers?: Record;
-}
-
-/**
- * Interface defining the input to the ChatMinimax class.
- */
-declare interface MinimaxChatInputBase {
- /** Model name to use
- * @default "abab5.5-chat"
- */
- modelName: string;
-
- /** Whether to stream the results or not. Defaults to false. */
- streaming?: boolean;
-
- prefixMessages?: MinimaxChatCompletionRequestMessage[];
-
- /**
- * API key to use when making requests. Defaults to the value of
- * `MINIMAX_GROUP_ID` environment variable.
- */
- minimaxGroupId?: string;
-
- /**
- * Secret key to use when making requests. Defaults to the value of
- * `MINIMAX_API_KEY` environment variable.
- */
- minimaxApiKey?: string;
-
- /** Amount of randomness injected into the response. Ranges
- * from 0 to 1 (0 is not included). Use temp closer to 0 for analytical /
- * multiple choice, and temp closer to 1 for creative
- * and generative tasks. Defaults to 0.95.
- */
- temperature?: number;
-
- /**
- * The smaller the sampling method, the more determinate the result;
- * the larger the number, the more random the result.
- */
- topP?: number;
-
- /**
- * Enable Chatcompletion pro
- */
- proVersion?: boolean;
-
- /**
- * Pay attention to the maximum number of tokens generated,
- * this parameter does not affect the generation effect of the model itself,
- * but only realizes the function by truncating the tokens exceeding the limit.
- * It is necessary to ensure that the number of tokens of the input context plus this value is less than 6144 or 16384,
- * otherwise the request will fail.
- */
- tokensToGenerate?: number;
-}
-
-declare interface MinimaxChatInputNormal {
- /**
- * Dialogue setting, characters, or functionality setting.
- */
- prompt?: string;
- /**
- * Sensitize text information in the output that may involve privacy issues,
- * currently including but not limited to emails, domain names,
- * links, ID numbers, home addresses, etc. Default false, ie. enable sensitization.
- */
- skipInfoMask?: boolean;
-
- /**
- * Whether to use the standard SSE format, when set to true,
- * the streaming results will be separated by two line breaks.
- * This parameter only takes effect when stream is set to true.
- */
- useStandardSse?: boolean;
-
- /**
- * If it is true, this indicates that the current request is set to continuation mode,
- * and the response is a continuation of the last sentence in the incoming messages;
- * at this time, the last sender is not limited to USER, it can also be BOT.
- * Assuming the last sentence of incoming messages is {"sender_type": " U S E R", "text": "天生我材"},
- * the completion of the reply may be "It must be useful."
- */
- continueLastMessage?: boolean;
-
- /**
- * How many results to generate; the default is 1 and the maximum is not more than 4.
- * Because beamWidth generates multiple results, it will consume more tokens.
- */
- beamWidth?: number;
-
- /**
- * Dialogue Metadata
- */
- roleMeta?: RoleMeta;
-}
-
-declare interface MinimaxChatInputPro extends MinimaxChatInputBase {
- /**
- * For the text information in the output that may involve privacy issues,
- * code masking is currently included but not limited to emails, domains, links, ID numbers, home addresses, etc.,
- * with the default being true, that is, code masking is enabled.
- */
- maskSensitiveInfo?: boolean;
-
- /**
- * Default bot name
- */
- defaultBotName?: string;
-
- /**
- * Default user name
- */
- defaultUserName?: string;
-
- /**
- * Setting for each robot, only available for pro version.
- */
- botSetting?: BotSetting[];
-
- replyConstraints?: ReplyConstraints;
-}
-
-type MinimaxChatInput = MinimaxChatInputNormal & MinimaxChatInputPro;
-
-/**
- * Function that extracts the custom sender_type of a generic chat message.
- * @param message Chat message from which to extract the custom sender_type.
- * @returns The custom sender_type of the chat message.
- */
-function extractGenericMessageCustomRole(message: ChatMessage) {
- if (message.role !== "ai" && message.role !== "user") {
- console.warn(`Unknown message role: ${message.role}`);
- }
- if (message.role === "ai") {
- return "BOT" as MinimaxMessageRole;
- }
- if (message.role === "user") {
- return "USER" as MinimaxMessageRole;
- }
- return message.role as MinimaxMessageRole;
-}
-
-/**
- * Function that converts a base message to a Minimax message sender_type.
- * @param message Base message to convert.
- * @returns The Minimax message sender_type.
- */
-function messageToMinimaxRole(message: BaseMessage): MinimaxMessageRole {
- const type = message._getType();
- switch (type) {
- case "ai":
- return "BOT";
- case "human":
- return "USER";
- case "system":
- throw new Error("System messages not supported");
- case "function":
- return "FUNCTION";
- case "generic": {
- if (!ChatMessage.isInstance(message))
- throw new Error("Invalid generic chat message");
- return extractGenericMessageCustomRole(message);
- }
- default:
- throw new Error(`Unknown message type: ${type}`);
- }
-}
-
-export interface ChatMinimaxCallOptions extends BaseFunctionCallOptions {
- tools?: StructuredTool[];
- defaultUserName?: string;
- defaultBotName?: string;
- plugins?: string[];
- botSetting?: BotSetting[];
- replyConstraints?: ReplyConstraints;
- sampleMessages?: BaseMessage[];
-}
-
-/**
- * Wrapper around Minimax large language models that use the Chat endpoint.
- *
- * To use you should have the `MINIMAX_GROUP_ID` and `MINIMAX_API_KEY`
- * environment variable set.
- * @example
- * ```typescript
- * // Define a chat prompt with a system message setting the context for translation
- * const chatPrompt = ChatPromptTemplate.fromMessages([
- * SystemMessagePromptTemplate.fromTemplate(
- * "You are a helpful assistant that translates {input_language} to {output_language}.",
- * ),
- * HumanMessagePromptTemplate.fromTemplate("{text}"),
- * ]);
- *
- * // Create a new LLMChain with the chat model and the defined prompt
- * const chainB = new LLMChain({
- * prompt: chatPrompt,
- * llm: new ChatMinimax({ temperature: 0.01 }),
- * });
- *
- * // Call the chain with the input language, output language, and the text to translate
- * const resB = await chainB.call({
- * input_language: "English",
- * output_language: "Chinese",
- * text: "I love programming.",
- * });
- *
- * // Log the result
- * console.log({ resB });
- *
- * ```
- */
-export class ChatMinimax
- extends BaseChatModel
- implements MinimaxChatInput
-{
- static lc_name() {
- return "ChatMinimax";
- }
-
- get callKeys(): (keyof ChatMinimaxCallOptions)[] {
- return [
- ...(super.callKeys as (keyof ChatMinimaxCallOptions)[]),
- "functions",
- "tools",
- "defaultBotName",
- "defaultUserName",
- "plugins",
- "replyConstraints",
- "botSetting",
- "sampleMessages",
- ];
- }
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- minimaxApiKey: "MINIMAX_API_KEY",
- minimaxGroupId: "MINIMAX_GROUP_ID",
- };
- }
-
- lc_serializable = true;
-
- minimaxGroupId?: string;
-
- minimaxApiKey?: string;
-
- streaming = false;
-
- prompt?: string;
-
- modelName = "abab5.5-chat";
-
- defaultBotName?: string = "Assistant";
-
- defaultUserName?: string = "I";
-
- prefixMessages?: MinimaxChatCompletionRequestMessage[];
-
- apiUrl: string;
-
- basePath?: string = "https://api.minimax.chat/v1";
-
- headers?: Record;
-
- temperature?: number = 0.9;
-
- topP?: number = 0.8;
-
- tokensToGenerate?: number;
-
- skipInfoMask?: boolean;
-
- proVersion?: boolean = true;
-
- beamWidth?: number;
-
- botSetting?: BotSetting[];
-
- continueLastMessage?: boolean;
-
- maskSensitiveInfo?: boolean;
-
- roleMeta?: RoleMeta;
-
- useStandardSse?: boolean;
-
- replyConstraints?: ReplyConstraints;
-
- constructor(
- fields?: Partial &
- BaseChatModelParams & {
- configuration?: ConfigurationParameters;
- }
- ) {
- super(fields ?? {});
-
- this.minimaxGroupId =
- fields?.minimaxGroupId ?? getEnvironmentVariable("MINIMAX_GROUP_ID");
- if (!this.minimaxGroupId) {
- throw new Error("Minimax GroupID not found");
- }
-
- this.minimaxApiKey =
- fields?.minimaxApiKey ?? getEnvironmentVariable("MINIMAX_API_KEY");
-
- if (!this.minimaxApiKey) {
- throw new Error("Minimax ApiKey not found");
- }
-
- this.streaming = fields?.streaming ?? this.streaming;
- this.prompt = fields?.prompt ?? this.prompt;
- this.temperature = fields?.temperature ?? this.temperature;
- this.topP = fields?.topP ?? this.topP;
- this.skipInfoMask = fields?.skipInfoMask ?? this.skipInfoMask;
- this.prefixMessages = fields?.prefixMessages ?? this.prefixMessages;
- this.maskSensitiveInfo =
- fields?.maskSensitiveInfo ?? this.maskSensitiveInfo;
- this.beamWidth = fields?.beamWidth ?? this.beamWidth;
- this.continueLastMessage =
- fields?.continueLastMessage ?? this.continueLastMessage;
- this.tokensToGenerate = fields?.tokensToGenerate ?? this.tokensToGenerate;
- this.roleMeta = fields?.roleMeta ?? this.roleMeta;
- this.botSetting = fields?.botSetting ?? this.botSetting;
- this.useStandardSse = fields?.useStandardSse ?? this.useStandardSse;
- this.replyConstraints = fields?.replyConstraints ?? this.replyConstraints;
- this.defaultBotName = fields?.defaultBotName ?? this.defaultBotName;
-
- this.modelName = fields?.modelName ?? this.modelName;
- this.basePath = fields?.configuration?.basePath ?? this.basePath;
- this.headers = fields?.configuration?.headers ?? this.headers;
- this.proVersion = fields?.proVersion ?? this.proVersion;
-
- const modelCompletion = this.proVersion
- ? "chatcompletion_pro"
- : "chatcompletion";
- this.apiUrl = `${this.basePath}/text/${modelCompletion}`;
- }
-
- fallbackBotName(options?: this["ParsedCallOptions"]) {
- let botName = options?.defaultBotName ?? this.defaultBotName ?? "Assistant";
- if (this.botSetting) {
- botName = this.botSetting[0].bot_name;
- }
- return botName;
- }
-
- defaultReplyConstraints(options?: this["ParsedCallOptions"]) {
- const constraints = options?.replyConstraints ?? this.replyConstraints;
- if (!constraints) {
- let botName =
- options?.defaultBotName ?? this.defaultBotName ?? "Assistant";
- if (this.botSetting) {
- botName = this.botSetting[0].bot_name;
- }
-
- return {
- sender_type: "BOT",
- sender_name: botName,
- };
- }
- return constraints;
- }
-
- /**
- * Get the parameters used to invoke the model
- */
- invocationParams(
- options?: this["ParsedCallOptions"]
- ): Omit {
- return {
- model: this.modelName,
- stream: this.streaming,
- prompt: this.prompt,
- temperature: this.temperature,
- top_p: this.topP,
- tokens_to_generate: this.tokensToGenerate,
- skip_info_mask: this.skipInfoMask,
- mask_sensitive_info: this.maskSensitiveInfo,
- beam_width: this.beamWidth,
- use_standard_sse: this.useStandardSse,
- role_meta: this.roleMeta,
- bot_setting: options?.botSetting ?? this.botSetting,
- reply_constraints: this.defaultReplyConstraints(options),
- sample_messages: this.messageToMinimaxMessage(
- options?.sampleMessages,
- options
- ),
- functions:
- options?.functions ??
- (options?.tools
- ? options?.tools.map(formatToOpenAIFunction)
- : undefined),
- plugins: options?.plugins,
- };
- }
-
- /**
- * Get the identifying parameters for the model
- */
- identifyingParams() {
- return {
- ...this.invocationParams(),
- };
- }
-
- /**
- * Convert a list of messages to the format expected by the model.
- * @param messages
- * @param options
- */
- messageToMinimaxMessage(
- messages?: BaseMessage[],
- options?: this["ParsedCallOptions"]
- ): MinimaxChatCompletionRequestMessage[] | undefined {
- return messages
- ?.filter((message) => {
- if (ChatMessage.isInstance(message)) {
- return message.role !== "system";
- }
- return message._getType() !== "system";
- })
- ?.map((message) => {
- const sender_type = messageToMinimaxRole(message);
- if (typeof message.content !== "string") {
- throw new Error(
- "ChatMinimax does not support non-string message content."
- );
- }
- return {
- sender_type,
- text: message.content,
- sender_name:
- message.name ??
- (sender_type === "BOT"
- ? this.fallbackBotName()
- : options?.defaultUserName ?? this.defaultUserName),
- };
- });
- }
-
- /** @ignore */
- async _generate(
- messages: BaseMessage[],
- options?: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): Promise {
- const tokenUsage = { totalTokens: 0 };
- this.botSettingFallback(options, messages);
-
- const params = this.invocationParams(options);
- const messagesMapped: MinimaxChatCompletionRequestMessage[] = [
- ...(this.messageToMinimaxMessage(messages, options) ?? []),
- ...(this.prefixMessages ?? []),
- ];
-
- const data = params.stream
- ? await new Promise((resolve, reject) => {
- let response: ChatCompletionResponse;
- let rejected = false;
- let resolved = false;
- this.completionWithRetry(
- {
- ...params,
- messages: messagesMapped,
- },
- true,
- options?.signal,
- (event) => {
- const data = JSON.parse(event.data);
-
- if (data?.error_code) {
- if (rejected) {
- return;
- }
- rejected = true;
- reject(data);
- return;
- }
-
- const message = data as ChatCompletionResponse;
- // on the first message set the response properties
-
- if (!message.choices[0].finish_reason) {
- // the last stream message
- let streamText;
- if (this.proVersion) {
- const messages = message.choices[0].messages ?? [];
- streamText = messages[0].text;
- } else {
- streamText = message.choices[0].delta;
- }
-
- // TODO this should pass part.index to the callback
- // when that's supported there
- // eslint-disable-next-line no-void
- void runManager?.handleLLMNewToken(streamText ?? "");
- return;
- }
-
- response = message;
- if (!this.proVersion) {
- response.choices[0].text = message.reply;
- }
-
- if (resolved || rejected) {
- return;
- }
- resolved = true;
- resolve(response);
- }
- ).catch((error) => {
- if (!rejected) {
- rejected = true;
- reject(error);
- }
- });
- })
- : await this.completionWithRetry(
- {
- ...params,
- messages: messagesMapped,
- },
- false,
- options?.signal
- );
-
- const { total_tokens: totalTokens } = data.usage ?? {};
-
- if (totalTokens) {
- tokenUsage.totalTokens = totalTokens;
- }
-
- if (data.base_resp?.status_code !== 0) {
- throw new Error(`Minimax API error: ${data.base_resp?.status_msg}`);
- }
- const generations: ChatGeneration[] = [];
-
- if (this.proVersion) {
- for (const choice of data.choices) {
- const messages = choice.messages ?? [];
- // 取最后一条消息
- if (messages) {
- const message = messages[messages.length - 1];
- const text = message?.text ?? "";
- generations.push({
- text,
- message: minimaxResponseToChatMessage(message),
- });
- }
- }
- } else {
- for (const choice of data.choices) {
- const text = choice?.text ?? "";
- generations.push({
- text,
- message: minimaxResponseToChatMessage({
- sender_type: "BOT",
- sender_name:
- options?.defaultBotName ?? this.defaultBotName ?? "Assistant",
- text,
- }),
- });
- }
- }
- return {
- generations,
- llmOutput: { tokenUsage },
- };
- }
-
- /** @ignore */
- async completionWithRetry(
- request: MinimaxChatCompletionRequest,
- stream: boolean,
- signal?: AbortSignal,
- onmessage?: (event: MessageEvent) => void
- ) {
- // The first run will get the accessToken
- const makeCompletionRequest = async () => {
- const url = `${this.apiUrl}?GroupId=${this.minimaxGroupId}`;
- const response = await fetch(url, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- Authorization: `Bearer ${this.minimaxApiKey}`,
- ...this.headers,
- },
- body: JSON.stringify(request),
- signal,
- });
-
- if (!stream) {
- const json = await response.json();
- return json as ChatCompletionResponse;
- } else {
- if (response.body) {
- const reader = response.body.getReader();
-
- const decoder = new TextDecoder("utf-8");
- let data = "";
-
- let continueReading = true;
- while (continueReading) {
- const { done, value } = await reader.read();
- if (done) {
- continueReading = false;
- break;
- }
- data += decoder.decode(value);
-
- let continueProcessing = true;
- while (continueProcessing) {
- const newlineIndex = data.indexOf("\n");
- if (newlineIndex === -1) {
- continueProcessing = false;
- break;
- }
- const line = data.slice(0, newlineIndex);
- data = data.slice(newlineIndex + 1);
-
- if (line.startsWith("data:")) {
- const event = new MessageEvent("message", {
- data: line.slice("data:".length).trim(),
- });
- onmessage?.(event);
- }
- }
- }
- return {} as ChatCompletionResponse;
- }
- return {} as ChatCompletionResponse;
- }
- };
- return this.caller.call(makeCompletionRequest);
- }
-
- _llmType() {
- return "minimax";
- }
-
- /** @ignore */
- _combineLLMOutput() {
- return [];
- }
-
- private botSettingFallback(
- options?: this["ParsedCallOptions"],
- messages?: BaseMessage[]
- ) {
- const botSettings = options?.botSetting ?? this.botSetting;
- if (!botSettings) {
- const systemMessages = messages?.filter((message) => {
- if (ChatMessage.isInstance(message)) {
- return message.role === "system";
- }
- return message._getType() === "system";
- });
-
- // get the last system message
- if (!systemMessages?.length) {
- return;
- }
- const lastSystemMessage = systemMessages[systemMessages.length - 1];
-
- if (typeof lastSystemMessage.content !== "string") {
- throw new Error(
- "ChatMinimax does not support non-string message content."
- );
- }
-
- // setting the default botSetting.
- this.botSetting = [
- {
- content: lastSystemMessage.content,
- bot_name:
- options?.defaultBotName ?? this.defaultBotName ?? "Assistant",
- },
- ];
- }
- }
-}
-
-function minimaxResponseToChatMessage(
- message: ChatCompletionResponseMessage
-): BaseMessage {
- switch (message.sender_type) {
- case "USER":
- return new HumanMessage(message.text || "");
- case "BOT":
- return new AIMessage(message.text || "", {
- function_call: message.function_call,
- });
- case "FUNCTION":
- return new AIMessage(message.text || "");
- default:
- return new ChatMessage(
- message.text || "",
- message.sender_type ?? "unknown"
- );
- }
-}
-
-/** ---Response Model---* */
-/**
- * Interface representing a message responsed in the Minimax chat model.
- */
-interface ChatCompletionResponseMessage {
- sender_type: MinimaxMessageRole;
- sender_name?: string;
- text: string;
- function_call?: ChatCompletionResponseMessageFunctionCall;
-}
-
-/**
- * Interface representing the usage of tokens in a chat completion.
- */
-interface TokenUsage {
- total_tokens?: number;
-}
-
-interface BaseResp {
- status_code?: number;
- status_msg?: string;
-}
-
-/**
- * The name and arguments of a function that should be called, as generated by the model.
- * @export
- * @interface ChatCompletionResponseMessageFunctionCall
- */
-export interface ChatCompletionResponseMessageFunctionCall {
- /**
- * The name of the function to call.
- * @type {string}
- * @memberof ChatCompletionResponseMessageFunctionCall
- */
- name?: string;
- /**
- * The arguments to call the function with, as generated by the model in JSON format. Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your function schema. Validate the arguments in your code before calling your function.
- * @type {string}
- * @memberof ChatCompletionResponseMessageFunctionCall
- */
- arguments?: string;
-}
-
-/**
- *
- * @export
- * @interface ChatCompletionResponseChoices
- */
-export interface ChatCompletionResponseChoicesPro {
- /**
- *
- * @type {string}
- * @memberof ChatCompletionResponseChoices
- */
- messages?: ChatCompletionResponseMessage[];
-
- /**
- *
- * @type {string}
- * @memberof ChatCompletionResponseChoices
- */
- finish_reason?: string;
-}
-
-interface ChatCompletionResponseChoices {
- delta?: string;
- text?: string;
- index?: number;
- finish_reason?: string;
-}
-
-/**
- * Interface representing a response from a chat completion.
- */
-interface ChatCompletionResponse {
- model: string;
- created: number;
- reply: string;
- input_sensitive?: boolean;
- input_sensitive_type?: number;
- output_sensitive?: boolean;
- output_sensitive_type?: number;
- usage?: TokenUsage;
- base_resp?: BaseResp;
- choices: Array<
- ChatCompletionResponseChoicesPro & ChatCompletionResponseChoices
- >;
-}
+export * from "@langchain/community/chat_models/minimax";
diff --git a/langchain/src/chat_models/ollama.ts b/langchain/src/chat_models/ollama.ts
index a3fbdb367eb2..175e84ab3511 100644
--- a/langchain/src/chat_models/ollama.ts
+++ b/langchain/src/chat_models/ollama.ts
@@ -1,298 +1 @@
-import { SimpleChatModel, BaseChatModelParams } from "./base.js";
-import { BaseLanguageModelCallOptions } from "../base_language/index.js";
-import { createOllamaStream, OllamaInput } from "../util/ollama.js";
-import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import {
- AIMessageChunk,
- BaseMessage,
- ChatGenerationChunk,
- ChatMessage,
-} from "../schema/index.js";
-import type { StringWithAutocomplete } from "../util/types.js";
-
-/**
- * An interface defining the options for an Ollama API call. It extends
- * the BaseLanguageModelCallOptions interface.
- */
-export interface OllamaCallOptions extends BaseLanguageModelCallOptions {}
-
-/**
- * A class that enables calls to the Ollama API to access large language
- * models in a chat-like fashion. It extends the SimpleChatModel class and
- * implements the OllamaInput interface.
- * @example
- * ```typescript
- * const prompt = ChatPromptTemplate.fromMessages([
- * [
- * "system",
- * `You are an expert translator. Format all responses as JSON objects with two keys: "original" and "translated".`,
- * ],
- * ["human", `Translate "{input}" into {language}.`],
- * ]);
- *
- * const model = new ChatOllama({
- * baseUrl: "http://api.example.com",
- * model: "llama2",
- * format: "json",
- * });
- *
- * const chain = prompt.pipe(model);
- *
- * const result = await chain.invoke({
- * input: "I love programming",
- * language: "German",
- * });
- *
- * ```
- */
-export class ChatOllama
- extends SimpleChatModel
- implements OllamaInput
-{
- static lc_name() {
- return "ChatOllama";
- }
-
- lc_serializable = true;
-
- model = "llama2";
-
- baseUrl = "http://localhost:11434";
-
- embeddingOnly?: boolean;
-
- f16KV?: boolean;
-
- frequencyPenalty?: number;
-
- logitsAll?: boolean;
-
- lowVram?: boolean;
-
- mainGpu?: number;
-
- mirostat?: number;
-
- mirostatEta?: number;
-
- mirostatTau?: number;
-
- numBatch?: number;
-
- numCtx?: number;
-
- numGpu?: number;
-
- numGqa?: number;
-
- numKeep?: number;
-
- numThread?: number;
-
- penalizeNewline?: boolean;
-
- presencePenalty?: number;
-
- repeatLastN?: number;
-
- repeatPenalty?: number;
-
- ropeFrequencyBase?: number;
-
- ropeFrequencyScale?: number;
-
- temperature?: number;
-
- stop?: string[];
-
- tfsZ?: number;
-
- topK?: number;
-
- topP?: number;
-
- typicalP?: number;
-
- useMLock?: boolean;
-
- useMMap?: boolean;
-
- vocabOnly?: boolean;
-
- format?: StringWithAutocomplete<"json">;
-
- constructor(fields: OllamaInput & BaseChatModelParams) {
- super(fields);
- this.model = fields.model ?? this.model;
- this.baseUrl = fields.baseUrl?.endsWith("/")
- ? fields.baseUrl.slice(0, -1)
- : fields.baseUrl ?? this.baseUrl;
- this.embeddingOnly = fields.embeddingOnly;
- this.f16KV = fields.f16KV;
- this.frequencyPenalty = fields.frequencyPenalty;
- this.logitsAll = fields.logitsAll;
- this.lowVram = fields.lowVram;
- this.mainGpu = fields.mainGpu;
- this.mirostat = fields.mirostat;
- this.mirostatEta = fields.mirostatEta;
- this.mirostatTau = fields.mirostatTau;
- this.numBatch = fields.numBatch;
- this.numCtx = fields.numCtx;
- this.numGpu = fields.numGpu;
- this.numGqa = fields.numGqa;
- this.numKeep = fields.numKeep;
- this.numThread = fields.numThread;
- this.penalizeNewline = fields.penalizeNewline;
- this.presencePenalty = fields.presencePenalty;
- this.repeatLastN = fields.repeatLastN;
- this.repeatPenalty = fields.repeatPenalty;
- this.ropeFrequencyBase = fields.ropeFrequencyBase;
- this.ropeFrequencyScale = fields.ropeFrequencyScale;
- this.temperature = fields.temperature;
- this.stop = fields.stop;
- this.tfsZ = fields.tfsZ;
- this.topK = fields.topK;
- this.topP = fields.topP;
- this.typicalP = fields.typicalP;
- this.useMLock = fields.useMLock;
- this.useMMap = fields.useMMap;
- this.vocabOnly = fields.vocabOnly;
- this.format = fields.format;
- }
-
- _llmType() {
- return "ollama";
- }
-
- /**
- * A method that returns the parameters for an Ollama API call. It
- * includes model and options parameters.
- * @param options Optional parsed call options.
- * @returns An object containing the parameters for an Ollama API call.
- */
- invocationParams(options?: this["ParsedCallOptions"]) {
- return {
- model: this.model,
- format: this.format,
- options: {
- embedding_only: this.embeddingOnly,
- f16_kv: this.f16KV,
- frequency_penalty: this.frequencyPenalty,
- logits_all: this.logitsAll,
- low_vram: this.lowVram,
- main_gpu: this.mainGpu,
- mirostat: this.mirostat,
- mirostat_eta: this.mirostatEta,
- mirostat_tau: this.mirostatTau,
- num_batch: this.numBatch,
- num_ctx: this.numCtx,
- num_gpu: this.numGpu,
- num_gqa: this.numGqa,
- num_keep: this.numKeep,
- num_thread: this.numThread,
- penalize_newline: this.penalizeNewline,
- presence_penalty: this.presencePenalty,
- repeat_last_n: this.repeatLastN,
- repeat_penalty: this.repeatPenalty,
- rope_frequency_base: this.ropeFrequencyBase,
- rope_frequency_scale: this.ropeFrequencyScale,
- temperature: this.temperature,
- stop: options?.stop ?? this.stop,
- tfs_z: this.tfsZ,
- top_k: this.topK,
- top_p: this.topP,
- typical_p: this.typicalP,
- use_mlock: this.useMLock,
- use_mmap: this.useMMap,
- vocab_only: this.vocabOnly,
- },
- };
- }
-
- _combineLLMOutput() {
- return {};
- }
-
- async *_streamResponseChunks(
- input: BaseMessage[],
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): AsyncGenerator {
- const stream = await this.caller.call(async () =>
- createOllamaStream(
- this.baseUrl,
- {
- ...this.invocationParams(options),
- prompt: this._formatMessagesAsPrompt(input),
- },
- options
- )
- );
- for await (const chunk of stream) {
- if (!chunk.done) {
- yield new ChatGenerationChunk({
- text: chunk.response,
- message: new AIMessageChunk({ content: chunk.response }),
- });
- await runManager?.handleLLMNewToken(chunk.response ?? "");
- } else {
- yield new ChatGenerationChunk({
- text: "",
- message: new AIMessageChunk({ content: "" }),
- generationInfo: {
- model: chunk.model,
- total_duration: chunk.total_duration,
- load_duration: chunk.load_duration,
- prompt_eval_count: chunk.prompt_eval_count,
- prompt_eval_duration: chunk.prompt_eval_duration,
- eval_count: chunk.eval_count,
- eval_duration: chunk.eval_duration,
- },
- });
- }
- }
- }
-
- protected _formatMessagesAsPrompt(messages: BaseMessage[]): string {
- const formattedMessages = messages
- .map((message) => {
- let messageText;
- if (message._getType() === "human") {
- messageText = `[INST] ${message.content} [/INST]`;
- } else if (message._getType() === "ai") {
- messageText = message.content;
- } else if (message._getType() === "system") {
- messageText = `<> ${message.content} <>`;
- } else if (ChatMessage.isInstance(message)) {
- messageText = `\n\n${message.role[0].toUpperCase()}${message.role.slice(
- 1
- )}: ${message.content}`;
- } else {
- console.warn(
- `Unsupported message type passed to Ollama: "${message._getType()}"`
- );
- messageText = "";
- }
- return messageText;
- })
- .join("\n");
- return formattedMessages;
- }
-
- /** @ignore */
- async _call(
- messages: BaseMessage[],
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): Promise {
- const chunks = [];
- for await (const chunk of this._streamResponseChunks(
- messages,
- options,
- runManager
- )) {
- chunks.push(chunk.message.content);
- }
- return chunks.join("");
- }
-}
+export * from "@langchain/community/chat_models/ollama";
diff --git a/langchain/src/chat_models/openai.ts b/langchain/src/chat_models/openai.ts
index c8e99c525246..cf822cb30a8d 100644
--- a/langchain/src/chat_models/openai.ts
+++ b/langchain/src/chat_models/openai.ts
@@ -1,836 +1,20 @@
-import { type ClientOptions, OpenAI as OpenAIClient } from "openai";
+import {
+ ChatOpenAI,
+ type ChatOpenAICallOptions,
+ messageToOpenAIRole,
+} from "@langchain/openai";
import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import {
- AIMessage,
- AIMessageChunk,
- BaseMessage,
- ChatGeneration,
- ChatGenerationChunk,
- ChatMessage,
- ChatMessageChunk,
- ChatResult,
- FunctionMessageChunk,
- HumanMessageChunk,
- SystemMessageChunk,
- ToolMessage,
- ToolMessageChunk,
-} from "../schema/index.js";
-import { StructuredTool } from "../tools/base.js";
-import { formatToOpenAITool } from "../tools/convert_to_openai.js";
-import {
- AzureOpenAIInput,
- OpenAICallOptions,
- OpenAIChatInput,
- OpenAICoreRequestOptions,
- LegacyOpenAIInput,
-} from "../types/openai-types.js";
-import { OpenAIEndpointConfig, getEndpoint } from "../util/azure.js";
-import { getEnvironmentVariable } from "../util/env.js";
+import { BaseMessage, ChatMessage, ChatResult } from "../schema/index.js";
import { promptLayerTrackRequest } from "../util/prompt-layer.js";
-import { BaseChatModel, BaseChatModelParams } from "./base.js";
-import { BaseFunctionCallOptions } from "../base_language/index.js";
-import { NewTokenIndices } from "../callbacks/base.js";
-import { wrapOpenAIClientError } from "../util/openai.js";
-import {
- FunctionDef,
- formatFunctionDefinitions,
-} from "../util/openai-format-fndef.js";
-
-export type { AzureOpenAIInput, OpenAICallOptions, OpenAIChatInput };
-
-interface TokenUsage {
- completionTokens?: number;
- promptTokens?: number;
- totalTokens?: number;
-}
-
-interface OpenAILLMOutput {
- tokenUsage: TokenUsage;
-}
-
-// TODO import from SDK when available
-type OpenAIRoleEnum = "system" | "assistant" | "user" | "function" | "tool";
-
-type OpenAICompletionParam =
- OpenAIClient.Chat.Completions.ChatCompletionMessageParam;
-type OpenAIFnDef = OpenAIClient.Chat.ChatCompletionCreateParams.Function;
-type OpenAIFnCallOption = OpenAIClient.Chat.ChatCompletionFunctionCallOption;
-
-function extractGenericMessageCustomRole(message: ChatMessage) {
- if (
- message.role !== "system" &&
- message.role !== "assistant" &&
- message.role !== "user" &&
- message.role !== "function" &&
- message.role !== "tool"
- ) {
- console.warn(`Unknown message role: ${message.role}`);
- }
-
- return message.role as OpenAIRoleEnum;
-}
-
-function messageToOpenAIRole(message: BaseMessage): OpenAIRoleEnum {
- const type = message._getType();
- switch (type) {
- case "system":
- return "system";
- case "ai":
- return "assistant";
- case "human":
- return "user";
- case "function":
- return "function";
- case "tool":
- return "tool";
- case "generic": {
- if (!ChatMessage.isInstance(message))
- throw new Error("Invalid generic chat message");
- return extractGenericMessageCustomRole(message);
- }
- default:
- throw new Error(`Unknown message type: ${type}`);
- }
-}
-
-function openAIResponseToChatMessage(
- message: OpenAIClient.Chat.Completions.ChatCompletionMessage
-): BaseMessage {
- switch (message.role) {
- case "assistant":
- return new AIMessage(message.content || "", {
- function_call: message.function_call,
- tool_calls: message.tool_calls,
- });
- default:
- return new ChatMessage(message.content || "", message.role ?? "unknown");
- }
-}
-
-function _convertDeltaToMessageChunk(
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- delta: Record,
- defaultRole?: OpenAIRoleEnum
-) {
- const role = delta.role ?? defaultRole;
- const content = delta.content ?? "";
- let additional_kwargs;
- if (delta.function_call) {
- additional_kwargs = {
- function_call: delta.function_call,
- };
- } else if (delta.tool_calls) {
- additional_kwargs = {
- tool_calls: delta.tool_calls,
- };
- } else {
- additional_kwargs = {};
- }
- if (role === "user") {
- return new HumanMessageChunk({ content });
- } else if (role === "assistant") {
- return new AIMessageChunk({ content, additional_kwargs });
- } else if (role === "system") {
- return new SystemMessageChunk({ content });
- } else if (role === "function") {
- return new FunctionMessageChunk({
- content,
- additional_kwargs,
- name: delta.name,
- });
- } else if (role === "tool") {
- return new ToolMessageChunk({
- content,
- additional_kwargs,
- tool_call_id: delta.tool_call_id,
- });
- } else {
- return new ChatMessageChunk({ content, role });
- }
-}
-
-function convertMessagesToOpenAIParams(messages: BaseMessage[]) {
- // TODO: Function messages do not support array content, fix cast
- return messages.map(
- (message) =>
- ({
- role: messageToOpenAIRole(message),
- content: message.content,
- name: message.name,
- function_call: message.additional_kwargs.function_call,
- tool_calls: message.additional_kwargs.tool_calls,
- tool_call_id: (message as ToolMessage).tool_call_id,
- } as OpenAICompletionParam)
- );
-}
-
-export interface ChatOpenAICallOptions
- extends OpenAICallOptions,
- BaseFunctionCallOptions {
- tools?: StructuredTool[] | OpenAIClient.ChatCompletionTool[];
- tool_choice?: OpenAIClient.ChatCompletionToolChoiceOption;
- promptIndex?: number;
- response_format?: { type: "json_object" };
- seed?: number;
-}
-
-/**
- * Wrapper around OpenAI large language models that use the Chat endpoint.
- *
- * To use you should have the `openai` package installed, with the
- * `OPENAI_API_KEY` environment variable set.
- *
- * To use with Azure you should have the `openai` package installed, with the
- * `AZURE_OPENAI_API_KEY`,
- * `AZURE_OPENAI_API_INSTANCE_NAME`,
- * `AZURE_OPENAI_API_DEPLOYMENT_NAME`
- * and `AZURE_OPENAI_API_VERSION` environment variable set.
- * `AZURE_OPENAI_BASE_PATH` is optional and will override `AZURE_OPENAI_API_INSTANCE_NAME` if you need to use a custom endpoint.
- *
- * @remarks
- * Any parameters that are valid to be passed to {@link
- * https://platform.openai.com/docs/api-reference/chat/create |
- * `openai.createChatCompletion`} can be passed through {@link modelKwargs}, even
- * if not explicitly available on this class.
- * @example
- * ```typescript
- * // Create a new instance of ChatOpenAI with specific temperature and model name settings
- * const model = new ChatOpenAI({
- * temperature: 0.9,
- * modelName: "ft:gpt-3.5-turbo-0613:{ORG_NAME}::{MODEL_ID}",
- * });
- *
- * // Invoke the model with a message and await the response
- * const message = await model.invoke("Hi there!");
- *
- * // Log the response to the console
- * console.log(message);
- *
- * ```
- */
-export class ChatOpenAI<
- CallOptions extends ChatOpenAICallOptions = ChatOpenAICallOptions
- >
- extends BaseChatModel
- implements OpenAIChatInput, AzureOpenAIInput
-{
- static lc_name() {
- return "ChatOpenAI";
- }
-
- get callKeys() {
- return [
- ...super.callKeys,
- "options",
- "function_call",
- "functions",
- "tools",
- "tool_choice",
- "promptIndex",
- "response_format",
- "seed",
- ];
- }
-
- lc_serializable = true;
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- openAIApiKey: "OPENAI_API_KEY",
- azureOpenAIApiKey: "AZURE_OPENAI_API_KEY",
- organization: "OPENAI_ORGANIZATION",
- };
- }
-
- get lc_aliases(): Record {
- return {
- modelName: "model",
- openAIApiKey: "openai_api_key",
- azureOpenAIApiVersion: "azure_openai_api_version",
- azureOpenAIApiKey: "azure_openai_api_key",
- azureOpenAIApiInstanceName: "azure_openai_api_instance_name",
- azureOpenAIApiDeploymentName: "azure_openai_api_deployment_name",
- };
- }
-
- temperature = 1;
-
- topP = 1;
-
- frequencyPenalty = 0;
-
- presencePenalty = 0;
-
- n = 1;
-
- logitBias?: Record;
-
- modelName = "gpt-3.5-turbo";
- modelKwargs?: OpenAIChatInput["modelKwargs"];
-
- stop?: string[];
-
- user?: string;
-
- timeout?: number;
-
- streaming = false;
-
- maxTokens?: number;
-
- openAIApiKey?: string;
-
- azureOpenAIApiVersion?: string;
-
- azureOpenAIApiKey?: string;
-
- azureOpenAIApiInstanceName?: string;
-
- azureOpenAIApiDeploymentName?: string;
-
- azureOpenAIBasePath?: string;
-
- organization?: string;
-
- private client: OpenAIClient;
-
- private clientConfig: ClientOptions;
-
- constructor(
- fields?: Partial &
- Partial &
- BaseChatModelParams & {
- configuration?: ClientOptions & LegacyOpenAIInput;
- },
- /** @deprecated */
- configuration?: ClientOptions & LegacyOpenAIInput
- ) {
- super(fields ?? {});
-
- this.openAIApiKey =
- fields?.openAIApiKey ?? getEnvironmentVariable("OPENAI_API_KEY");
-
- this.azureOpenAIApiKey =
- fields?.azureOpenAIApiKey ??
- getEnvironmentVariable("AZURE_OPENAI_API_KEY");
-
- if (!this.azureOpenAIApiKey && !this.openAIApiKey) {
- throw new Error("OpenAI or Azure OpenAI API key not found");
- }
-
- this.azureOpenAIApiInstanceName =
- fields?.azureOpenAIApiInstanceName ??
- getEnvironmentVariable("AZURE_OPENAI_API_INSTANCE_NAME");
-
- this.azureOpenAIApiDeploymentName =
- fields?.azureOpenAIApiDeploymentName ??
- getEnvironmentVariable("AZURE_OPENAI_API_DEPLOYMENT_NAME");
-
- this.azureOpenAIApiVersion =
- fields?.azureOpenAIApiVersion ??
- getEnvironmentVariable("AZURE_OPENAI_API_VERSION");
-
- this.azureOpenAIBasePath =
- fields?.azureOpenAIBasePath ??
- getEnvironmentVariable("AZURE_OPENAI_BASE_PATH");
-
- this.organization =
- fields?.configuration?.organization ??
- getEnvironmentVariable("OPENAI_ORGANIZATION");
-
- this.modelName = fields?.modelName ?? this.modelName;
- this.modelKwargs = fields?.modelKwargs ?? {};
- this.timeout = fields?.timeout;
-
- this.temperature = fields?.temperature ?? this.temperature;
- this.topP = fields?.topP ?? this.topP;
- this.frequencyPenalty = fields?.frequencyPenalty ?? this.frequencyPenalty;
- this.presencePenalty = fields?.presencePenalty ?? this.presencePenalty;
- this.maxTokens = fields?.maxTokens;
- this.n = fields?.n ?? this.n;
- this.logitBias = fields?.logitBias;
- this.stop = fields?.stop;
- this.user = fields?.user;
-
- this.streaming = fields?.streaming ?? false;
-
- if (this.azureOpenAIApiKey) {
- if (!this.azureOpenAIApiInstanceName && !this.azureOpenAIBasePath) {
- throw new Error("Azure OpenAI API instance name not found");
- }
- if (!this.azureOpenAIApiDeploymentName) {
- throw new Error("Azure OpenAI API deployment name not found");
- }
- if (!this.azureOpenAIApiVersion) {
- throw new Error("Azure OpenAI API version not found");
- }
- this.openAIApiKey = this.openAIApiKey ?? "";
- }
-
- this.clientConfig = {
- apiKey: this.openAIApiKey,
- organization: this.organization,
- baseURL: configuration?.basePath ?? fields?.configuration?.basePath,
- dangerouslyAllowBrowser: true,
- defaultHeaders:
- configuration?.baseOptions?.headers ??
- fields?.configuration?.baseOptions?.headers,
- defaultQuery:
- configuration?.baseOptions?.params ??
- fields?.configuration?.baseOptions?.params,
- ...configuration,
- ...fields?.configuration,
- };
- }
-
- /**
- * Get the parameters used to invoke the model
- */
- invocationParams(
- options?: this["ParsedCallOptions"]
- ): Omit {
- function isStructuredToolArray(
- tools?: unknown[]
- ): tools is StructuredTool[] {
- return (
- tools !== undefined &&
- tools.every((tool) =>
- Array.isArray((tool as StructuredTool).lc_namespace)
- )
- );
- }
- const params: Omit<
- OpenAIClient.Chat.ChatCompletionCreateParams,
- "messages"
- > = {
- model: this.modelName,
- temperature: this.temperature,
- top_p: this.topP,
- frequency_penalty: this.frequencyPenalty,
- presence_penalty: this.presencePenalty,
- max_tokens: this.maxTokens === -1 ? undefined : this.maxTokens,
- n: this.n,
- logit_bias: this.logitBias,
- stop: options?.stop ?? this.stop,
- user: this.user,
- stream: this.streaming,
- functions: options?.functions,
- function_call: options?.function_call,
- tools: isStructuredToolArray(options?.tools)
- ? options?.tools.map(formatToOpenAITool)
- : options?.tools,
- tool_choice: options?.tool_choice,
- response_format: options?.response_format,
- seed: options?.seed,
- ...this.modelKwargs,
- };
- return params;
- }
-
- /** @ignore */
- _identifyingParams(): Omit<
- OpenAIClient.Chat.ChatCompletionCreateParams,
- "messages"
- > & {
- model_name: string;
- } & ClientOptions {
- return {
- model_name: this.modelName,
- ...this.invocationParams(),
- ...this.clientConfig,
- };
- }
-
- async *_streamResponseChunks(
- messages: BaseMessage[],
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): AsyncGenerator {
- const messagesMapped: OpenAICompletionParam[] =
- convertMessagesToOpenAIParams(messages);
- const params = {
- ...this.invocationParams(options),
- messages: messagesMapped,
- stream: true as const,
- };
- let defaultRole: OpenAIRoleEnum | undefined;
- const streamIterable = await this.completionWithRetry(params, options);
- for await (const data of streamIterable) {
- const choice = data?.choices[0];
- if (!choice) {
- continue;
- }
+export {
+ type AzureOpenAIInput,
+ type OpenAICallOptions,
+ type OpenAIChatInput,
+} from "@langchain/openai";
- const { delta } = choice;
- if (!delta) {
- continue;
- }
- const chunk = _convertDeltaToMessageChunk(delta, defaultRole);
- defaultRole = delta.role ?? defaultRole;
- const newTokenIndices = {
- prompt: options.promptIndex ?? 0,
- completion: choice.index ?? 0,
- };
- if (typeof chunk.content !== "string") {
- console.log(
- "[WARNING]: Received non-string content from OpenAI. This is currently not supported."
- );
- continue;
- }
- const generationChunk = new ChatGenerationChunk({
- message: chunk,
- text: chunk.content,
- generationInfo: newTokenIndices,
- });
- yield generationChunk;
- // eslint-disable-next-line no-void
- void runManager?.handleLLMNewToken(
- generationChunk.text ?? "",
- newTokenIndices,
- undefined,
- undefined,
- undefined,
- { chunk: generationChunk }
- );
- }
- if (options.signal?.aborted) {
- throw new Error("AbortError");
- }
- }
-
- /**
- * Get the identifying parameters for the model
- *
- */
- identifyingParams() {
- return this._identifyingParams();
- }
-
- /** @ignore */
- async _generate(
- messages: BaseMessage[],
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): Promise {
- const tokenUsage: TokenUsage = {};
- const params = this.invocationParams(options);
- const messagesMapped: OpenAICompletionParam[] =
- convertMessagesToOpenAIParams(messages);
-
- if (params.stream) {
- const stream = this._streamResponseChunks(messages, options, runManager);
- const finalChunks: Record = {};
- for await (const chunk of stream) {
- const index =
- (chunk.generationInfo as NewTokenIndices)?.completion ?? 0;
- if (finalChunks[index] === undefined) {
- finalChunks[index] = chunk;
- } else {
- finalChunks[index] = finalChunks[index].concat(chunk);
- }
- }
- const generations = Object.entries(finalChunks)
- .sort(([aKey], [bKey]) => parseInt(aKey, 10) - parseInt(bKey, 10))
- .map(([_, value]) => value);
-
- const { functions, function_call } = this.invocationParams(options);
-
- // OpenAI does not support token usage report under stream mode,
- // fallback to estimation.
-
- const promptTokenUsage = await this.getEstimatedTokenCountFromPrompt(
- messages,
- functions,
- function_call
- );
- const completionTokenUsage = await this.getNumTokensFromGenerations(
- generations
- );
-
- tokenUsage.promptTokens = promptTokenUsage;
- tokenUsage.completionTokens = completionTokenUsage;
- tokenUsage.totalTokens = promptTokenUsage + completionTokenUsage;
- return { generations, llmOutput: { estimatedTokenUsage: tokenUsage } };
- } else {
- const data = await this.completionWithRetry(
- {
- ...params,
- stream: false,
- messages: messagesMapped,
- },
- {
- signal: options?.signal,
- ...options?.options,
- }
- );
- const {
- completion_tokens: completionTokens,
- prompt_tokens: promptTokens,
- total_tokens: totalTokens,
- } = data?.usage ?? {};
-
- if (completionTokens) {
- tokenUsage.completionTokens =
- (tokenUsage.completionTokens ?? 0) + completionTokens;
- }
-
- if (promptTokens) {
- tokenUsage.promptTokens = (tokenUsage.promptTokens ?? 0) + promptTokens;
- }
-
- if (totalTokens) {
- tokenUsage.totalTokens = (tokenUsage.totalTokens ?? 0) + totalTokens;
- }
-
- const generations: ChatGeneration[] = [];
- for (const part of data?.choices ?? []) {
- const text = part.message?.content ?? "";
- const generation: ChatGeneration = {
- text,
- message: openAIResponseToChatMessage(
- part.message ?? { role: "assistant" }
- ),
- };
- if (part.finish_reason) {
- generation.generationInfo = { finish_reason: part.finish_reason };
- }
- generations.push(generation);
- }
- return {
- generations,
- llmOutput: { tokenUsage },
- };
- }
- }
-
- /**
- * Estimate the number of tokens a prompt will use.
- * Modified from: https://github.com/hmarr/openai-chat-tokens/blob/main/src/index.ts
- */
- private async getEstimatedTokenCountFromPrompt(
- messages: BaseMessage[],
- functions?: OpenAIFnDef[],
- function_call?: "none" | "auto" | OpenAIFnCallOption
- ): Promise {
- // It appears that if functions are present, the first system message is padded with a trailing newline. This
- // was inferred by trying lots of combinations of messages and functions and seeing what the token counts were.
-
- let tokens = (await this.getNumTokensFromMessages(messages)).totalCount;
-
- // If there are functions, add the function definitions as they count towards token usage
- if (functions && function_call !== "auto") {
- const promptDefinitions = formatFunctionDefinitions(
- functions as unknown as FunctionDef[]
- );
- tokens += await this.getNumTokens(promptDefinitions);
- tokens += 9; // Add nine per completion
- }
-
- // If there's a system message _and_ functions are present, subtract four tokens. I assume this is because
- // functions typically add a system message, but reuse the first one if it's already there. This offsets
- // the extra 9 tokens added by the function definitions.
- if (functions && messages.find((m) => m._getType() === "system")) {
- tokens -= 4;
- }
-
- // If function_call is 'none', add one token.
- // If it's a FunctionCall object, add 4 + the number of tokens in the function name.
- // If it's undefined or 'auto', don't add anything.
- if (function_call === "none") {
- tokens += 1;
- } else if (typeof function_call === "object") {
- tokens += (await this.getNumTokens(function_call.name)) + 4;
- }
-
- return tokens;
- }
-
- /**
- * Estimate the number of tokens an array of generations have used.
- */
- private async getNumTokensFromGenerations(generations: ChatGeneration[]) {
- const generationUsages = await Promise.all(
- generations.map(async (generation) => {
- if (generation.message.additional_kwargs?.function_call) {
- return (await this.getNumTokensFromMessages([generation.message]))
- .countPerMessage[0];
- } else {
- return await this.getNumTokens(generation.message.content);
- }
- })
- );
-
- return generationUsages.reduce((a, b) => a + b, 0);
- }
-
- async getNumTokensFromMessages(messages: BaseMessage[]) {
- let totalCount = 0;
- let tokensPerMessage = 0;
- let tokensPerName = 0;
-
- // From: https://github.com/openai/openai-cookbook/blob/main/examples/How_to_format_inputs_to_ChatGPT_models.ipynb
- if (this.modelName === "gpt-3.5-turbo-0301") {
- tokensPerMessage = 4;
- tokensPerName = -1;
- } else {
- tokensPerMessage = 3;
- tokensPerName = 1;
- }
-
- const countPerMessage = await Promise.all(
- messages.map(async (message) => {
- const textCount = await this.getNumTokens(message.content);
- const roleCount = await this.getNumTokens(messageToOpenAIRole(message));
- const nameCount =
- message.name !== undefined
- ? tokensPerName + (await this.getNumTokens(message.name))
- : 0;
- let count = textCount + tokensPerMessage + roleCount + nameCount;
-
- // From: https://github.com/hmarr/openai-chat-tokens/blob/main/src/index.ts messageTokenEstimate
- const openAIMessage = message;
- if (openAIMessage._getType() === "function") {
- count -= 2;
- }
- if (openAIMessage.additional_kwargs?.function_call) {
- count += 3;
- }
- if (openAIMessage?.additional_kwargs.function_call?.name) {
- count += await this.getNumTokens(
- openAIMessage.additional_kwargs.function_call?.name
- );
- }
- if (openAIMessage.additional_kwargs.function_call?.arguments) {
- count += await this.getNumTokens(
- // Remove newlines and spaces
- JSON.stringify(
- JSON.parse(
- openAIMessage.additional_kwargs.function_call?.arguments
- )
- )
- );
- }
-
- totalCount += count;
- return count;
- })
- );
-
- totalCount += 3; // every reply is primed with <|start|>assistant<|message|>
-
- return { totalCount, countPerMessage };
- }
-
- /**
- * Calls the OpenAI API with retry logic in case of failures.
- * @param request The request to send to the OpenAI API.
- * @param options Optional configuration for the API call.
- * @returns The response from the OpenAI API.
- */
- async completionWithRetry(
- request: OpenAIClient.Chat.ChatCompletionCreateParamsStreaming,
- options?: OpenAICoreRequestOptions
- ): Promise>;
-
- async completionWithRetry(
- request: OpenAIClient.Chat.ChatCompletionCreateParamsNonStreaming,
- options?: OpenAICoreRequestOptions
- ): Promise;
-
- async completionWithRetry(
- request:
- | OpenAIClient.Chat.ChatCompletionCreateParamsStreaming
- | OpenAIClient.Chat.ChatCompletionCreateParamsNonStreaming,
- options?: OpenAICoreRequestOptions
- ): Promise<
- | AsyncIterable
- | OpenAIClient.Chat.Completions.ChatCompletion
- > {
- const requestOptions = this._getClientOptions(options);
- return this.caller.call(async () => {
- try {
- const res = await this.client.chat.completions.create(
- request,
- requestOptions
- );
- return res;
- } catch (e) {
- const error = wrapOpenAIClientError(e);
- throw error;
- }
- });
- }
-
- private _getClientOptions(options: OpenAICoreRequestOptions | undefined) {
- if (!this.client) {
- const openAIEndpointConfig: OpenAIEndpointConfig = {
- azureOpenAIApiDeploymentName: this.azureOpenAIApiDeploymentName,
- azureOpenAIApiInstanceName: this.azureOpenAIApiInstanceName,
- azureOpenAIApiKey: this.azureOpenAIApiKey,
- azureOpenAIBasePath: this.azureOpenAIBasePath,
- baseURL: this.clientConfig.baseURL,
- };
-
- const endpoint = getEndpoint(openAIEndpointConfig);
- const params = {
- ...this.clientConfig,
- baseURL: endpoint,
- timeout: this.timeout,
- maxRetries: 0,
- };
- if (!params.baseURL) {
- delete params.baseURL;
- }
-
- this.client = new OpenAIClient(params);
- }
- const requestOptions = {
- ...this.clientConfig,
- ...options,
- } as OpenAICoreRequestOptions;
- if (this.azureOpenAIApiKey) {
- requestOptions.headers = {
- "api-key": this.azureOpenAIApiKey,
- ...requestOptions.headers,
- };
- requestOptions.query = {
- "api-version": this.azureOpenAIApiVersion,
- ...requestOptions.query,
- };
- }
- return requestOptions;
- }
-
- _llmType() {
- return "openai";
- }
-
- /** @ignore */
- _combineLLMOutput(...llmOutputs: OpenAILLMOutput[]): OpenAILLMOutput {
- return llmOutputs.reduce<{
- [key in keyof OpenAILLMOutput]: Required;
- }>(
- (acc, llmOutput) => {
- if (llmOutput && llmOutput.tokenUsage) {
- acc.tokenUsage.completionTokens +=
- llmOutput.tokenUsage.completionTokens ?? 0;
- acc.tokenUsage.promptTokens += llmOutput.tokenUsage.promptTokens ?? 0;
- acc.tokenUsage.totalTokens += llmOutput.tokenUsage.totalTokens ?? 0;
- }
- return acc;
- },
- {
- tokenUsage: {
- completionTokens: 0,
- promptTokens: 0,
- totalTokens: 0,
- },
- }
- );
- }
-}
+export { type ChatOpenAICallOptions, ChatOpenAI };
export class PromptLayerChatOpenAI extends ChatOpenAI {
promptLayerApiKey?: string;
diff --git a/langchain/src/chat_models/portkey.ts b/langchain/src/chat_models/portkey.ts
index fd41231b9ac3..41b8ae09537c 100644
--- a/langchain/src/chat_models/portkey.ts
+++ b/langchain/src/chat_models/portkey.ts
@@ -1,182 +1 @@
-import { LLMOptions } from "portkey-ai";
-import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import { PortkeySession, getPortkeySession } from "../llms/portkey.js";
-import {
- AIMessage,
- AIMessageChunk,
- BaseMessage,
- ChatGeneration,
- ChatGenerationChunk,
- ChatMessage,
- ChatMessageChunk,
- ChatResult,
- FunctionMessageChunk,
- HumanMessage,
- HumanMessageChunk,
- SystemMessage,
- SystemMessageChunk,
-} from "../schema/index.js";
-import { BaseChatModel } from "./base.js";
-
-interface Message {
- role?: string;
- content?: string;
-}
-
-function portkeyResponseToChatMessage(message: Message): BaseMessage {
- switch (message.role) {
- case "user":
- return new HumanMessage(message.content || "");
- case "assistant":
- return new AIMessage(message.content || "");
- case "system":
- return new SystemMessage(message.content || "");
- default:
- return new ChatMessage(message.content || "", message.role ?? "unknown");
- }
-}
-
-function _convertDeltaToMessageChunk(
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- delta: Record
-) {
- const { role } = delta;
- const content = delta.content ?? "";
- let additional_kwargs;
- if (delta.function_call) {
- additional_kwargs = {
- function_call: delta.function_call,
- };
- } else {
- additional_kwargs = {};
- }
- if (role === "user") {
- return new HumanMessageChunk({ content });
- } else if (role === "assistant") {
- return new AIMessageChunk({ content, additional_kwargs });
- } else if (role === "system") {
- return new SystemMessageChunk({ content });
- } else if (role === "function") {
- return new FunctionMessageChunk({
- content,
- additional_kwargs,
- name: delta.name,
- });
- } else {
- return new ChatMessageChunk({ content, role });
- }
-}
-
-export class PortkeyChat extends BaseChatModel {
- apiKey?: string = undefined;
-
- baseURL?: string = undefined;
-
- mode?: string = undefined;
-
- llms?: [LLMOptions] | null = undefined;
-
- session: PortkeySession;
-
- constructor(init?: Partial) {
- super(init ?? {});
- this.apiKey = init?.apiKey;
- this.baseURL = init?.baseURL;
- this.mode = init?.mode;
- this.llms = init?.llms;
- this.session = getPortkeySession({
- apiKey: this.apiKey,
- baseURL: this.baseURL,
- llms: this.llms,
- mode: this.mode,
- });
- }
-
- _llmType() {
- return "portkey";
- }
-
- async _generate(
- messages: BaseMessage[],
- options: this["ParsedCallOptions"],
- _?: CallbackManagerForLLMRun
- ): Promise {
- const messagesList = messages.map((message) => {
- if (typeof message.content !== "string") {
- throw new Error(
- "PortkeyChat does not support non-string message content."
- );
- }
- return {
- role: message._getType() as string,
- content: message.content,
- };
- });
- const response = await this.session.portkey.chatCompletions.create({
- messages: messagesList,
- ...options,
- stream: false,
- });
- const generations: ChatGeneration[] = [];
- for (const data of response.choices ?? []) {
- const text = data.message?.content ?? "";
- const generation: ChatGeneration = {
- text,
- message: portkeyResponseToChatMessage(data.message ?? {}),
- };
- if (data.finish_reason) {
- generation.generationInfo = { finish_reason: data.finish_reason };
- }
- generations.push(generation);
- }
-
- return {
- generations,
- };
- }
-
- async *_streamResponseChunks(
- messages: BaseMessage[],
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): AsyncGenerator {
- const messagesList = messages.map((message) => {
- if (typeof message.content !== "string") {
- throw new Error(
- "PortkeyChat does not support non-string message content."
- );
- }
- return {
- role: message._getType() as string,
- content: message.content,
- };
- });
- const response = await this.session.portkey.chatCompletions.create({
- messages: messagesList,
- ...options,
- stream: true,
- });
- for await (const data of response) {
- const choice = data?.choices[0];
- if (!choice) {
- continue;
- }
- const chunk = new ChatGenerationChunk({
- message: _convertDeltaToMessageChunk(choice.delta ?? {}),
- text: choice.message?.content ?? "",
- generationInfo: {
- finishReason: choice.finish_reason,
- },
- });
- yield chunk;
- void runManager?.handleLLMNewToken(chunk.text ?? "");
- }
- if (options.signal?.aborted) {
- throw new Error("AbortError");
- }
- }
-
- _combineLLMOutput() {
- return {};
- }
-}
+export * from "@langchain/community/chat_models/portkey";
diff --git a/langchain/src/chat_models/yandex.ts b/langchain/src/chat_models/yandex.ts
index 5365183792ca..3dbac8ffb540 100644
--- a/langchain/src/chat_models/yandex.ts
+++ b/langchain/src/chat_models/yandex.ts
@@ -1,142 +1 @@
-import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import { YandexGPTInputs } from "../llms/yandex.js";
-import {
- AIMessage,
- BaseMessage,
- ChatResult,
- ChatGeneration,
-} from "../schema/index.js";
-import { getEnvironmentVariable } from "../util/env.js";
-import { BaseChatModel } from "./base.js";
-
-const apiUrl = "https://llm.api.cloud.yandex.net/llm/v1alpha/chat";
-
-interface ParsedMessage {
- role: string;
- text: string;
-}
-
-function _parseChatHistory(history: BaseMessage[]): [ParsedMessage[], string] {
- const chatHistory: ParsedMessage[] = [];
- let instruction = "";
-
- for (const message of history) {
- if (typeof message.content !== "string") {
- throw new Error(
- "ChatYandexGPT does not support non-string message content."
- );
- }
- if ("content" in message) {
- if (message._getType() === "human") {
- chatHistory.push({ role: "user", text: message.content });
- } else if (message._getType() === "ai") {
- chatHistory.push({ role: "assistant", text: message.content });
- } else if (message._getType() === "system") {
- instruction = message.content;
- }
- }
- }
-
- return [chatHistory, instruction];
-}
-
-/**
- * @example
- * ```typescript
- * const chat = new ChatYandexGPT({});
- * // The assistant is set to translate English to French.
- * const res = await chat.call([
- * new SystemMessage(
- * "You are a helpful assistant that translates English to French."
- * ),
- * new HumanMessage("I love programming."),
- * ]);
- * console.log(res);
- * ```
- */
-export class ChatYandexGPT extends BaseChatModel {
- apiKey?: string;
-
- iamToken?: string;
-
- temperature = 0.6;
-
- maxTokens = 1700;
-
- model = "general";
-
- constructor(fields?: YandexGPTInputs) {
- super(fields ?? {});
-
- const apiKey = fields?.apiKey ?? getEnvironmentVariable("YC_API_KEY");
-
- const iamToken = fields?.iamToken ?? getEnvironmentVariable("YC_IAM_TOKEN");
-
- if (apiKey === undefined && iamToken === undefined) {
- throw new Error(
- "Please set the YC_API_KEY or YC_IAM_TOKEN environment variable or pass it to the constructor as the apiKey or iamToken field."
- );
- }
-
- this.apiKey = apiKey;
- this.iamToken = iamToken;
- this.maxTokens = fields?.maxTokens ?? this.maxTokens;
- this.temperature = fields?.temperature ?? this.temperature;
- this.model = fields?.model ?? this.model;
- }
-
- _llmType() {
- return "yandexgpt";
- }
-
- _combineLLMOutput?() {
- return {};
- }
-
- /** @ignore */
- async _generate(
- messages: BaseMessage[],
- options: this["ParsedCallOptions"],
- _?: CallbackManagerForLLMRun | undefined
- ): Promise {
- const [messageHistory, instruction] = _parseChatHistory(messages);
- const headers = { "Content-Type": "application/json", Authorization: "" };
- if (this.apiKey !== undefined) {
- headers.Authorization = `Api-Key ${this.apiKey}`;
- } else {
- headers.Authorization = `Bearer ${this.iamToken}`;
- }
- const bodyData = {
- model: this.model,
- generationOptions: {
- temperature: this.temperature,
- maxTokens: this.maxTokens,
- },
- messages: messageHistory,
- instructionText: instruction,
- };
- const response = await fetch(apiUrl, {
- method: "POST",
- headers,
- body: JSON.stringify(bodyData),
- signal: options?.signal,
- });
- if (!response.ok) {
- throw new Error(
- `Failed to fetch ${apiUrl} from YandexGPT: ${response.status}`
- );
- }
- const responseData = await response.json();
- const { result } = responseData;
- const { text } = result.message;
- const totalTokens = result.num_tokens;
- const generations: ChatGeneration[] = [
- { text, message: new AIMessage(text) },
- ];
-
- return {
- generations,
- llmOutput: { totalTokens },
- };
- }
-}
+export * from "@langchain/community/chat_models/yandex";
diff --git a/langchain/src/document_loaders/fs/openai_whisper_audio.ts b/langchain/src/document_loaders/fs/openai_whisper_audio.ts
index fbbdbef6f25b..468eba28c1e5 100644
--- a/langchain/src/document_loaders/fs/openai_whisper_audio.ts
+++ b/langchain/src/document_loaders/fs/openai_whisper_audio.ts
@@ -1,4 +1,4 @@
-import { type ClientOptions, OpenAI as OpenAIClient, toFile } from "openai";
+import { type ClientOptions, OpenAIClient, toFile } from "@langchain/openai";
import { Document } from "../../document.js";
import { BufferLoader } from "./buffer.js";
diff --git a/langchain/src/document_transformers/html_to_text.ts b/langchain/src/document_transformers/html_to_text.ts
index 987d1c6feed3..a3d4023dfdd0 100644
--- a/langchain/src/document_transformers/html_to_text.ts
+++ b/langchain/src/document_transformers/html_to_text.ts
@@ -1,43 +1 @@
-import { htmlToText } from "html-to-text";
-import type { HtmlToTextOptions } from "html-to-text";
-import { Document } from "../document.js";
-import { MappingDocumentTransformer } from "../schema/document.js";
-
-/**
- * A transformer that converts HTML content to plain text.
- * @example
- * ```typescript
- * const loader = new CheerioWebBaseLoader("https://example.com/some-page");
- * const docs = await loader.load();
- *
- * const splitter = new RecursiveCharacterTextSplitter({
- * maxCharacterCount: 1000,
- * });
- * const transformer = new HtmlToTextTransformer();
- *
- * // The sequence of text splitting followed by HTML to text transformation
- * const sequence = splitter.pipe(transformer);
- *
- * // Processing the loaded documents through the sequence
- * const newDocuments = await sequence.invoke(docs);
- *
- * console.log(newDocuments);
- * ```
- */
-export class HtmlToTextTransformer extends MappingDocumentTransformer {
- static lc_name() {
- return "HtmlToTextTransformer";
- }
-
- constructor(protected options: HtmlToTextOptions = {}) {
- super(options);
- }
-
- async _transformDocument(document: Document): Promise {
- const extractedContent = htmlToText(document.pageContent, this.options);
- return new Document({
- pageContent: extractedContent,
- metadata: { ...document.metadata },
- });
- }
-}
+export * from "@langchain/community/document_transformers/html_to_text";
diff --git a/langchain/src/document_transformers/mozilla_readability.ts b/langchain/src/document_transformers/mozilla_readability.ts
index 1eb302bbbc38..481f786c13d0 100644
--- a/langchain/src/document_transformers/mozilla_readability.ts
+++ b/langchain/src/document_transformers/mozilla_readability.ts
@@ -1,52 +1 @@
-import { Readability } from "@mozilla/readability";
-import { JSDOM } from "jsdom";
-import { Options } from "mozilla-readability";
-import { Document } from "../document.js";
-import { MappingDocumentTransformer } from "../schema/document.js";
-
-/**
- * A transformer that uses the Mozilla Readability library to extract the
- * main content from a web page.
- * @example
- * ```typescript
- * const loader = new CheerioWebBaseLoader("https://example.com/article");
- * const docs = await loader.load();
- *
- * const splitter = new RecursiveCharacterTextSplitter({
- * maxCharacterCount: 5000,
- * });
- * const transformer = new MozillaReadabilityTransformer();
- *
- * // The sequence processes the loaded documents through the splitter and then the transformer.
- * const sequence = splitter.pipe(transformer);
- *
- * // Invoke the sequence to transform the documents into a more readable format.
- * const newDocuments = await sequence.invoke(docs);
- *
- * console.log(newDocuments);
- * ```
- */
-export class MozillaReadabilityTransformer extends MappingDocumentTransformer {
- static lc_name() {
- return "MozillaReadabilityTransformer";
- }
-
- constructor(protected options: Options = {}) {
- super(options);
- }
-
- async _transformDocument(document: Document): Promise {
- const doc = new JSDOM(document.pageContent);
-
- const readability = new Readability(doc.window.document, this.options);
-
- const result = readability.parse();
-
- return new Document({
- pageContent: result?.textContent ?? "",
- metadata: {
- ...document.metadata,
- },
- });
- }
-}
+export * from "@langchain/community/document_transformers/mozilla_readability";
diff --git a/langchain/src/embeddings/bedrock.ts b/langchain/src/embeddings/bedrock.ts
index f9ca960f3a1a..0158430fd0a5 100644
--- a/langchain/src/embeddings/bedrock.ts
+++ b/langchain/src/embeddings/bedrock.ts
@@ -1,142 +1 @@
-import {
- BedrockRuntimeClient,
- InvokeModelCommand,
-} from "@aws-sdk/client-bedrock-runtime";
-import { Embeddings, EmbeddingsParams } from "./base.js";
-import type { CredentialType } from "../util/bedrock.js";
-
-/**
- * Interface that extends EmbeddingsParams and defines additional
- * parameters specific to the BedrockEmbeddings class.
- */
-export interface BedrockEmbeddingsParams extends EmbeddingsParams {
- /**
- * Model Name to use. Defaults to `amazon.titan-embed-text-v1` if not provided
- *
- */
- model?: string;
-
- /**
- * A client provided by the user that allows them to customze any
- * SDK configuration options.
- */
- client?: BedrockRuntimeClient;
-
- region?: string;
-
- credentials?: CredentialType;
-}
-
-/**
- * Class that extends the Embeddings class and provides methods for
- * generating embeddings using the Bedrock API.
- * @example
- * ```typescript
- * const embeddings = new BedrockEmbeddings({
- * region: "your-aws-region",
- * credentials: {
- * accessKeyId: "your-access-key-id",
- * secretAccessKey: "your-secret-access-key",
- * },
- * model: "amazon.titan-embed-text-v1",
- * });
- *
- * // Embed a query and log the result
- * const res = await embeddings.embedQuery(
- * "What would be a good company name for a company that makes colorful socks?"
- * );
- * console.log({ res });
- * ```
- */
-export class BedrockEmbeddings
- extends Embeddings
- implements BedrockEmbeddingsParams
-{
- model: string;
-
- client: BedrockRuntimeClient;
-
- batchSize = 512;
-
- constructor(fields?: BedrockEmbeddingsParams) {
- super(fields ?? {});
-
- this.model = fields?.model ?? "amazon.titan-embed-text-v1";
-
- this.client =
- fields?.client ??
- new BedrockRuntimeClient({
- region: fields?.region,
- credentials: fields?.credentials,
- });
- }
-
- /**
- * Protected method to make a request to the Bedrock API to generate
- * embeddings. Handles the retry logic and returns the response from the
- * API.
- * @param request Request to send to the Bedrock API.
- * @returns Promise that resolves to the response from the API.
- */
- protected async _embedText(text: string): Promise {
- return this.caller.call(async () => {
- try {
- // replace newlines, which can negatively affect performance.
- const cleanedText = text.replace(/\n/g, " ");
-
- const res = await this.client.send(
- new InvokeModelCommand({
- modelId: this.model,
- body: JSON.stringify({
- inputText: cleanedText,
- }),
- contentType: "application/json",
- accept: "application/json",
- })
- );
-
- const body = new TextDecoder().decode(res.body);
- return JSON.parse(body).embedding;
- } catch (e) {
- console.error({
- error: e,
- });
- // eslint-disable-next-line no-instanceof/no-instanceof
- if (e instanceof Error) {
- throw new Error(
- `An error occurred while embedding documents with Bedrock: ${e.message}`
- );
- }
-
- throw new Error(
- "An error occurred while embedding documents with Bedrock"
- );
- }
- });
- }
-
- /**
- * Method that takes a document as input and returns a promise that
- * resolves to an embedding for the document. It calls the _embedText
- * method with the document as the input.
- * @param document Document for which to generate an embedding.
- * @returns Promise that resolves to an embedding for the input document.
- */
- embedQuery(document: string): Promise {
- return this.caller.callWithOptions(
- {},
- this._embedText.bind(this),
- document
- );
- }
-
- /**
- * Method to generate embeddings for an array of texts. Calls _embedText
- * method which batches and handles retry logic when calling the AWS Bedrock API.
- * @param documents Array of texts for which to generate embeddings.
- * @returns Promise that resolves to a 2D array of embeddings for each input document.
- */
- async embedDocuments(documents: string[]): Promise {
- return Promise.all(documents.map((document) => this._embedText(document)));
- }
-}
+export * from "@langchain/community/embeddings/bedrock";
diff --git a/langchain/src/embeddings/cloudflare_workersai.ts b/langchain/src/embeddings/cloudflare_workersai.ts
index 191213dfbf5f..b5d4cd6238a8 100644
--- a/langchain/src/embeddings/cloudflare_workersai.ts
+++ b/langchain/src/embeddings/cloudflare_workersai.ts
@@ -1,94 +1 @@
-import { Ai } from "@cloudflare/ai";
-import { Fetcher } from "@cloudflare/workers-types";
-import { chunkArray } from "../util/chunk.js";
-import { Embeddings, EmbeddingsParams } from "./base.js";
-
-type AiTextEmbeddingsInput = {
- text: string | string[];
-};
-
-type AiTextEmbeddingsOutput = {
- shape: number[];
- data: number[][];
-};
-
-export interface CloudflareWorkersAIEmbeddingsParams extends EmbeddingsParams {
- /** Binding */
- binding: Fetcher;
-
- /** Model name to use */
- modelName?: string;
-
- /**
- * The maximum number of documents to embed in a single request.
- */
- batchSize?: number;
-
- /**
- * Whether to strip new lines from the input text. This is recommended by
- * OpenAI, but may not be suitable for all use cases.
- */
- stripNewLines?: boolean;
-}
-
-export class CloudflareWorkersAIEmbeddings extends Embeddings {
- modelName = "@cf/baai/bge-base-en-v1.5";
-
- batchSize = 50;
-
- stripNewLines = true;
-
- ai: Ai;
-
- constructor(fields: CloudflareWorkersAIEmbeddingsParams) {
- super(fields);
-
- if (!fields.binding) {
- throw new Error(
- "Must supply a Workers AI binding, eg { binding: env.AI }"
- );
- }
- this.ai = new Ai(fields.binding);
- this.modelName = fields.modelName ?? this.modelName;
- this.stripNewLines = fields.stripNewLines ?? this.stripNewLines;
- }
-
- async embedDocuments(texts: string[]): Promise {
- const batches = chunkArray(
- this.stripNewLines ? texts.map((t) => t.replace(/\n/g, " ")) : texts,
- this.batchSize
- );
-
- const batchRequests = batches.map((batch) => this.runEmbedding(batch));
- const batchResponses = await Promise.all(batchRequests);
- const embeddings: number[][] = [];
-
- for (let i = 0; i < batchResponses.length; i += 1) {
- const batchResponse = batchResponses[i];
- for (let j = 0; j < batchResponse.length; j += 1) {
- embeddings.push(batchResponse[j]);
- }
- }
-
- return embeddings;
- }
-
- async embedQuery(text: string): Promise {
- const data = await this.runEmbedding([
- this.stripNewLines ? text.replace(/\n/g, " ") : text,
- ]);
- return data[0];
- }
-
- private async runEmbedding(texts: string[]) {
- return this.caller.call(async () => {
- const response: AiTextEmbeddingsOutput = await this.ai.run(
- this.modelName,
- {
- text: texts,
- } as AiTextEmbeddingsInput
- );
- return response.data;
- });
- }
-}
+export * from "@langchain/community/embeddings/cloudflare_workersai";
diff --git a/langchain/src/embeddings/cohere.ts b/langchain/src/embeddings/cohere.ts
index 4d510c205459..83eb358d4e37 100644
--- a/langchain/src/embeddings/cohere.ts
+++ b/langchain/src/embeddings/cohere.ts
@@ -1,155 +1 @@
-import { chunkArray } from "../util/chunk.js";
-import { getEnvironmentVariable } from "../util/env.js";
-import { Embeddings, EmbeddingsParams } from "./base.js";
-
-/**
- * Interface that extends EmbeddingsParams and defines additional
- * parameters specific to the CohereEmbeddings class.
- */
-export interface CohereEmbeddingsParams extends EmbeddingsParams {
- modelName: string;
-
- /**
- * The maximum number of documents to embed in a single request. This is
- * limited by the Cohere API to a maximum of 96.
- */
- batchSize?: number;
-}
-
-/**
- * A class for generating embeddings using the Cohere API.
- * @example
- * ```typescript
- * // Embed a query using the CohereEmbeddings class
- * const model = new ChatOpenAI();
- * const res = await model.embedQuery(
- * "What would be a good company name for a company that makes colorful socks?",
- * );
- * console.log({ res });
- *
- * ```
- */
-export class CohereEmbeddings
- extends Embeddings
- implements CohereEmbeddingsParams
-{
- modelName = "small";
-
- batchSize = 48;
-
- private apiKey: string;
-
- private client: typeof import("cohere-ai");
-
- /**
- * Constructor for the CohereEmbeddings class.
- * @param fields - An optional object with properties to configure the instance.
- */
- constructor(
- fields?: Partial & {
- verbose?: boolean;
- apiKey?: string;
- }
- ) {
- const fieldsWithDefaults = { maxConcurrency: 2, ...fields };
-
- super(fieldsWithDefaults);
-
- const apiKey =
- fieldsWithDefaults?.apiKey || getEnvironmentVariable("COHERE_API_KEY");
-
- if (!apiKey) {
- throw new Error("Cohere API key not found");
- }
-
- this.modelName = fieldsWithDefaults?.modelName ?? this.modelName;
- this.batchSize = fieldsWithDefaults?.batchSize ?? this.batchSize;
- this.apiKey = apiKey;
- }
-
- /**
- * Generates embeddings for an array of texts.
- * @param texts - An array of strings to generate embeddings for.
- * @returns A Promise that resolves to an array of embeddings.
- */
- async embedDocuments(texts: string[]): Promise {
- await this.maybeInitClient();
-
- const batches = chunkArray(texts, this.batchSize);
-
- const batchRequests = batches.map((batch) =>
- this.embeddingWithRetry({
- model: this.modelName,
- texts: batch,
- })
- );
-
- const batchResponses = await Promise.all(batchRequests);
-
- const embeddings: number[][] = [];
-
- for (let i = 0; i < batchResponses.length; i += 1) {
- const batch = batches[i];
- const { body: batchResponse } = batchResponses[i];
- for (let j = 0; j < batch.length; j += 1) {
- embeddings.push(batchResponse.embeddings[j]);
- }
- }
-
- return embeddings;
- }
-
- /**
- * Generates an embedding for a single text.
- * @param text - A string to generate an embedding for.
- * @returns A Promise that resolves to an array of numbers representing the embedding.
- */
- async embedQuery(text: string): Promise {
- await this.maybeInitClient();
-
- const { body } = await this.embeddingWithRetry({
- model: this.modelName,
- texts: [text],
- });
- return body.embeddings[0];
- }
-
- /**
- * Generates embeddings with retry capabilities.
- * @param request - An object containing the request parameters for generating embeddings.
- * @returns A Promise that resolves to the API response.
- */
- private async embeddingWithRetry(
- request: Parameters[0]
- ) {
- await this.maybeInitClient();
-
- return this.caller.call(this.client.embed.bind(this.client), request);
- }
-
- /**
- * Initializes the Cohere client if it hasn't been initialized already.
- */
- private async maybeInitClient() {
- if (!this.client) {
- const { cohere } = await CohereEmbeddings.imports();
-
- this.client = cohere;
- this.client.init(this.apiKey);
- }
- }
-
- /** @ignore */
- static async imports(): Promise<{
- cohere: typeof import("cohere-ai");
- }> {
- try {
- const { default: cohere } = await import("cohere-ai");
- return { cohere };
- } catch (e) {
- throw new Error(
- "Please install cohere-ai as a dependency with, e.g. `yarn add cohere-ai`"
- );
- }
- }
-}
+export * from "@langchain/community/embeddings/cohere";
diff --git a/langchain/src/embeddings/googlepalm.ts b/langchain/src/embeddings/googlepalm.ts
index 2d969dc98106..950bc455c2c6 100644
--- a/langchain/src/embeddings/googlepalm.ts
+++ b/langchain/src/embeddings/googlepalm.ts
@@ -1,107 +1 @@
-import { TextServiceClient } from "@google-ai/generativelanguage";
-import { GoogleAuth } from "google-auth-library";
-import { Embeddings, EmbeddingsParams } from "./base.js";
-import { getEnvironmentVariable } from "../util/env.js";
-
-/**
- * Interface that extends EmbeddingsParams and defines additional
- * parameters specific to the GooglePaLMEmbeddings class.
- */
-export interface GooglePaLMEmbeddingsParams extends EmbeddingsParams {
- /**
- * Model Name to use
- *
- * Note: The format must follow the pattern - `models/{model}`
- */
- modelName?: string;
- /**
- * Google Palm API key to use
- */
- apiKey?: string;
-}
-
-/**
- * Class that extends the Embeddings class and provides methods for
- * generating embeddings using the Google Palm API.
- * @example
- * ```typescript
- * const model = new GooglePaLMEmbeddings({
- * apiKey: "",
- * modelName: "models/embedding-gecko-001",
- * });
- *
- * // Embed a single query
- * const res = await model.embedQuery(
- * "What would be a good company name for a company that makes colorful socks?"
- * );
- * console.log({ res });
- *
- * // Embed multiple documents
- * const documentRes = await model.embedDocuments(["Hello world", "Bye bye"]);
- * console.log({ documentRes });
- * ```
- */
-export class GooglePaLMEmbeddings
- extends Embeddings
- implements GooglePaLMEmbeddingsParams
-{
- apiKey?: string;
-
- modelName = "models/embedding-gecko-001";
-
- private client: TextServiceClient;
-
- constructor(fields?: GooglePaLMEmbeddingsParams) {
- super(fields ?? {});
-
- this.modelName = fields?.modelName ?? this.modelName;
-
- this.apiKey =
- fields?.apiKey ?? getEnvironmentVariable("GOOGLE_PALM_API_KEY");
- if (!this.apiKey) {
- throw new Error(
- "Please set an API key for Google Palm 2 in the environment variable GOOGLE_PALM_API_KEY or in the `apiKey` field of the GooglePalm constructor"
- );
- }
-
- this.client = new TextServiceClient({
- authClient: new GoogleAuth().fromAPIKey(this.apiKey),
- });
- }
-
- protected async _embedText(text: string): Promise {
- // replace newlines, which can negatively affect performance.
- const cleanedText = text.replace(/\n/g, " ");
- const res = await this.client.embedText({
- model: this.modelName,
- text: cleanedText,
- });
- return res[0].embedding?.value ?? [];
- }
-
- /**
- * Method that takes a document as input and returns a promise that
- * resolves to an embedding for the document. It calls the _embedText
- * method with the document as the input.
- * @param document Document for which to generate an embedding.
- * @returns Promise that resolves to an embedding for the input document.
- */
- embedQuery(document: string): Promise {
- return this.caller.callWithOptions(
- {},
- this._embedText.bind(this),
- document
- );
- }
-
- /**
- * Method that takes an array of documents as input and returns a promise
- * that resolves to a 2D array of embeddings for each document. It calls
- * the _embedText method for each document in the array.
- * @param documents Array of documents for which to generate embeddings.
- * @returns Promise that resolves to a 2D array of embeddings for each input document.
- */
- embedDocuments(documents: string[]): Promise {
- return Promise.all(documents.map((document) => this._embedText(document)));
- }
-}
+export * from "@langchain/community/embeddings/googlepalm";
diff --git a/langchain/src/embeddings/googlevertexai.ts b/langchain/src/embeddings/googlevertexai.ts
index 121d8c6efd9b..3eded4165344 100644
--- a/langchain/src/embeddings/googlevertexai.ts
+++ b/langchain/src/embeddings/googlevertexai.ts
@@ -1,145 +1 @@
-import { GoogleAuth, GoogleAuthOptions } from "google-auth-library";
-import { Embeddings, EmbeddingsParams } from "./base.js";
-import {
- GoogleVertexAIBasePrediction,
- GoogleVertexAIBaseLLMInput,
- GoogleVertexAILLMPredictions,
-} from "../types/googlevertexai-types.js";
-import { GoogleVertexAILLMConnection } from "../util/googlevertexai-connection.js";
-import { AsyncCallerCallOptions } from "../util/async_caller.js";
-import { chunkArray } from "../util/chunk.js";
-
-/**
- * Defines the parameters required to initialize a
- * GoogleVertexAIEmbeddings instance. It extends EmbeddingsParams and
- * GoogleVertexAIConnectionParams.
- */
-export interface GoogleVertexAIEmbeddingsParams
- extends EmbeddingsParams,
- GoogleVertexAIBaseLLMInput {}
-
-/**
- * Defines additional options specific to the
- * GoogleVertexAILLMEmbeddingsInstance. It extends AsyncCallerCallOptions.
- */
-interface GoogleVertexAILLMEmbeddingsOptions extends AsyncCallerCallOptions {}
-
-/**
- * Represents an instance for generating embeddings using the Google
- * Vertex AI API. It contains the content to be embedded.
- */
-interface GoogleVertexAILLMEmbeddingsInstance {
- content: string;
-}
-
-/**
- * Defines the structure of the embeddings results returned by the Google
- * Vertex AI API. It extends GoogleVertexAIBasePrediction and contains the
- * embeddings and their statistics.
- */
-interface GoogleVertexEmbeddingsResults extends GoogleVertexAIBasePrediction {
- embeddings: {
- statistics: {
- token_count: number;
- truncated: boolean;
- };
- values: number[];
- };
-}
-
-/**
- * Enables calls to the Google Cloud's Vertex AI API to access
- * the embeddings generated by Large Language Models.
- *
- * To use, you will need to have one of the following authentication
- * methods in place:
- * - You are logged into an account permitted to the Google Cloud project
- * using Vertex AI.
- * - You are running this on a machine using a service account permitted to
- * the Google Cloud project using Vertex AI.
- * - The `GOOGLE_APPLICATION_CREDENTIALS` environment variable is set to the
- * path of a credentials file for a service account permitted to the
- * Google Cloud project using Vertex AI.
- * @example
- * ```typescript
- * const model = new GoogleVertexAIEmbeddings();
- * const res = await model.embedQuery(
- * "What would be a good company name for a company that makes colorful socks?"
- * );
- * console.log({ res });
- * ```
- */
-export class GoogleVertexAIEmbeddings
- extends Embeddings
- implements GoogleVertexAIEmbeddingsParams
-{
- model = "textembedding-gecko";
-
- private connection: GoogleVertexAILLMConnection<
- GoogleVertexAILLMEmbeddingsOptions,
- GoogleVertexAILLMEmbeddingsInstance,
- GoogleVertexEmbeddingsResults,
- GoogleAuthOptions
- >;
-
- constructor(fields?: GoogleVertexAIEmbeddingsParams) {
- super(fields ?? {});
-
- this.model = fields?.model ?? this.model;
-
- this.connection = new GoogleVertexAILLMConnection(
- { ...fields, ...this },
- this.caller,
- new GoogleAuth({
- scopes: "https://www.googleapis.com/auth/cloud-platform",
- ...fields?.authOptions,
- })
- );
- }
-
- /**
- * Takes an array of documents as input and returns a promise that
- * resolves to a 2D array of embeddings for each document. It splits the
- * documents into chunks and makes requests to the Google Vertex AI API to
- * generate embeddings.
- * @param documents An array of documents to be embedded.
- * @returns A promise that resolves to a 2D array of embeddings for each document.
- */
- async embedDocuments(documents: string[]): Promise {
- const instanceChunks: GoogleVertexAILLMEmbeddingsInstance[][] = chunkArray(
- documents.map((document) => ({
- content: document,
- })),
- 5
- ); // Vertex AI accepts max 5 instances per prediction
- const parameters = {};
- const options = {};
- const responses = await Promise.all(
- instanceChunks.map((instances) =>
- this.connection.request(instances, parameters, options)
- )
- );
- const result: number[][] =
- responses
- ?.map(
- (response) =>
- (
- response?.data as GoogleVertexAILLMPredictions
- )?.predictions?.map((result) => result.embeddings.values) ?? []
- )
- .flat() ?? [];
- return result;
- }
-
- /**
- * Takes a document as input and returns a promise that resolves to an
- * embedding for the document. It calls the embedDocuments method with the
- * document as the input.
- * @param document A document to be embedded.
- * @returns A promise that resolves to an embedding for the document.
- */
- async embedQuery(document: string): Promise {
- const data = await this.embedDocuments([document]);
- return data[0];
- }
-}
+export * from "@langchain/community/embeddings/googlevertexai";
diff --git a/langchain/src/embeddings/gradient_ai.ts b/langchain/src/embeddings/gradient_ai.ts
index e03b7a364c0f..83b02683d3d9 100644
--- a/langchain/src/embeddings/gradient_ai.ts
+++ b/langchain/src/embeddings/gradient_ai.ts
@@ -1,118 +1 @@
-import { Gradient } from "@gradientai/nodejs-sdk";
-import { getEnvironmentVariable } from "../util/env.js";
-import { chunkArray } from "../util/chunk.js";
-import { Embeddings, EmbeddingsParams } from "./base.js";
-
-/**
- * Interface for GradientEmbeddings parameters. Extends EmbeddingsParams and
- * defines additional parameters specific to the GradientEmbeddings class.
- */
-export interface GradientEmbeddingsParams extends EmbeddingsParams {
- /**
- * Gradient AI Access Token.
- * Provide Access Token if you do not wish to automatically pull from env.
- */
- gradientAccessKey?: string;
- /**
- * Gradient Workspace Id.
- * Provide workspace id if you do not wish to automatically pull from env.
- */
- workspaceId?: string;
-}
-
-/**
- * Class for generating embeddings using the Gradient AI's API. Extends the
- * Embeddings class and implements GradientEmbeddingsParams and
- */
-export class GradientEmbeddings
- extends Embeddings
- implements GradientEmbeddingsParams
-{
- gradientAccessKey?: string;
-
- workspaceId?: string;
-
- batchSize = 128;
-
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- model: any;
-
- constructor(fields: GradientEmbeddingsParams) {
- super(fields);
-
- this.gradientAccessKey =
- fields?.gradientAccessKey ??
- getEnvironmentVariable("GRADIENT_ACCESS_TOKEN");
- this.workspaceId =
- fields?.workspaceId ?? getEnvironmentVariable("GRADIENT_WORKSPACE_ID");
-
- if (!this.gradientAccessKey) {
- throw new Error("Missing Gradient AI Access Token");
- }
-
- if (!this.workspaceId) {
- throw new Error("Missing Gradient AI Workspace ID");
- }
- }
-
- /**
- * Method to generate embeddings for an array of documents. Splits the
- * documents into batches and makes requests to the Gradient API to generate
- * embeddings.
- * @param texts Array of documents to generate embeddings for.
- * @returns Promise that resolves to a 2D array of embeddings for each document.
- */
- async embedDocuments(texts: string[]): Promise {
- await this.setModel();
-
- const mappedTexts = texts.map((text) => ({ input: text }));
-
- const batches = chunkArray(mappedTexts, this.batchSize);
-
- const batchRequests = batches.map((batch) =>
- this.caller.call(async () =>
- this.model.generateEmbeddings({
- inputs: batch,
- })
- )
- );
- const batchResponses = await Promise.all(batchRequests);
-
- const embeddings: number[][] = [];
- for (let i = 0; i < batchResponses.length; i += 1) {
- const batch = batches[i];
- const { embeddings: batchResponse } = batchResponses[i];
- for (let j = 0; j < batch.length; j += 1) {
- embeddings.push(batchResponse[j].embedding);
- }
- }
- return embeddings;
- }
-
- /**
- * Method to generate an embedding for a single document. Calls the
- * embedDocuments method with the document as the input.
- * @param text Document to generate an embedding for.
- * @returns Promise that resolves to an embedding for the document.
- */
- async embedQuery(text: string): Promise {
- const data = await this.embedDocuments([text]);
- return data[0];
- }
-
- /**
- * Method to set the model to use for generating embeddings.
- * @sets the class' `model` value to that of the retrieved Embeddings Model.
- */
- async setModel() {
- if (this.model) return;
-
- const gradient = new Gradient({
- accessToken: this.gradientAccessKey,
- workspaceId: this.workspaceId,
- });
- this.model = await gradient.getEmbeddingsModel({
- slug: "bge-large",
- });
- }
-}
+export * from "@langchain/community/embeddings/gradient_ai";
diff --git a/langchain/src/embeddings/hf.ts b/langchain/src/embeddings/hf.ts
index 83b801a90566..7042535179ed 100644
--- a/langchain/src/embeddings/hf.ts
+++ b/langchain/src/embeddings/hf.ts
@@ -1,77 +1 @@
-import { HfInference, HfInferenceEndpoint } from "@huggingface/inference";
-import { Embeddings, EmbeddingsParams } from "./base.js";
-import { getEnvironmentVariable } from "../util/env.js";
-
-/**
- * Interface that extends EmbeddingsParams and defines additional
- * parameters specific to the HuggingFaceInferenceEmbeddings class.
- */
-export interface HuggingFaceInferenceEmbeddingsParams extends EmbeddingsParams {
- apiKey?: string;
- model?: string;
- endpointUrl?: string;
-}
-
-/**
- * Class that extends the Embeddings class and provides methods for
- * generating embeddings using Hugging Face models through the
- * HuggingFaceInference API.
- */
-export class HuggingFaceInferenceEmbeddings
- extends Embeddings
- implements HuggingFaceInferenceEmbeddingsParams
-{
- apiKey?: string;
-
- model: string;
-
- endpointUrl?: string;
-
- client: HfInference | HfInferenceEndpoint;
-
- constructor(fields?: HuggingFaceInferenceEmbeddingsParams) {
- super(fields ?? {});
-
- this.model = fields?.model ?? "BAAI/bge-base-en-v1.5";
- this.apiKey =
- fields?.apiKey ?? getEnvironmentVariable("HUGGINGFACEHUB_API_KEY");
- this.endpointUrl = fields?.endpointUrl;
- this.client = this.endpointUrl
- ? new HfInference(this.apiKey).endpoint(this.endpointUrl)
- : new HfInference(this.apiKey);
- }
-
- async _embed(texts: string[]): Promise {
- // replace newlines, which can negatively affect performance.
- const clean = texts.map((text) => text.replace(/\n/g, " "));
- return this.caller.call(() =>
- this.client.featureExtraction({
- model: this.model,
- inputs: clean,
- })
- ) as Promise;
- }
-
- /**
- * Method that takes a document as input and returns a promise that
- * resolves to an embedding for the document. It calls the _embed method
- * with the document as the input and returns the first embedding in the
- * resulting array.
- * @param document Document to generate an embedding for.
- * @returns Promise that resolves to an embedding for the document.
- */
- embedQuery(document: string): Promise {
- return this._embed([document]).then((embeddings) => embeddings[0]);
- }
-
- /**
- * Method that takes an array of documents as input and returns a promise
- * that resolves to a 2D array of embeddings for each document. It calls
- * the _embed method with the documents as the input.
- * @param documents Array of documents to generate embeddings for.
- * @returns Promise that resolves to a 2D array of embeddings for each document.
- */
- embedDocuments(documents: string[]): Promise {
- return this._embed(documents);
- }
-}
+export * from "@langchain/community/embeddings/hf";
diff --git a/langchain/src/embeddings/hf_transformers.ts b/langchain/src/embeddings/hf_transformers.ts
index e2b8bdcc98a5..aff3ec98244e 100644
--- a/langchain/src/embeddings/hf_transformers.ts
+++ b/langchain/src/embeddings/hf_transformers.ts
@@ -1,105 +1 @@
-import { Pipeline, pipeline } from "@xenova/transformers";
-import { chunkArray } from "../util/chunk.js";
-import { Embeddings, EmbeddingsParams } from "./base.js";
-
-export interface HuggingFaceTransformersEmbeddingsParams
- extends EmbeddingsParams {
- /** Model name to use */
- modelName: string;
-
- /**
- * Timeout to use when making requests to OpenAI.
- */
- timeout?: number;
-
- /**
- * The maximum number of documents to embed in a single request.
- */
- batchSize?: number;
-
- /**
- * Whether to strip new lines from the input text. This is recommended by
- * OpenAI, but may not be suitable for all use cases.
- */
- stripNewLines?: boolean;
-}
-
-/**
- * @example
- * ```typescript
- * const model = new HuggingFaceTransformersEmbeddings({
- * modelName: "Xenova/all-MiniLM-L6-v2",
- * });
- *
- * // Embed a single query
- * const res = await model.embedQuery(
- * "What would be a good company name for a company that makes colorful socks?"
- * );
- * console.log({ res });
- *
- * // Embed multiple documents
- * const documentRes = await model.embedDocuments(["Hello world", "Bye bye"]);
- * console.log({ documentRes });
- * ```
- */
-export class HuggingFaceTransformersEmbeddings
- extends Embeddings
- implements HuggingFaceTransformersEmbeddingsParams
-{
- modelName = "Xenova/all-MiniLM-L6-v2";
-
- batchSize = 512;
-
- stripNewLines = true;
-
- timeout?: number;
-
- private pipelinePromise: Promise;
-
- constructor(fields?: Partial) {
- super(fields ?? {});
-
- this.modelName = fields?.modelName ?? this.modelName;
- this.stripNewLines = fields?.stripNewLines ?? this.stripNewLines;
- this.timeout = fields?.timeout;
- }
-
- async embedDocuments(texts: string[]): Promise {
- const batches = chunkArray(
- this.stripNewLines ? texts.map((t) => t.replace(/\n/g, " ")) : texts,
- this.batchSize
- );
-
- const batchRequests = batches.map((batch) => this.runEmbedding(batch));
- const batchResponses = await Promise.all(batchRequests);
- const embeddings: number[][] = [];
-
- for (let i = 0; i < batchResponses.length; i += 1) {
- const batchResponse = batchResponses[i];
- for (let j = 0; j < batchResponse.length; j += 1) {
- embeddings.push(batchResponse[j]);
- }
- }
-
- return embeddings;
- }
-
- async embedQuery(text: string): Promise {
- const data = await this.runEmbedding([
- this.stripNewLines ? text.replace(/\n/g, " ") : text,
- ]);
- return data[0];
- }
-
- private async runEmbedding(texts: string[]) {
- const pipe = await (this.pipelinePromise ??= pipeline(
- "feature-extraction",
- this.modelName
- ));
-
- return this.caller.call(async () => {
- const output = await pipe(texts, { pooling: "mean", normalize: true });
- return output.tolist();
- });
- }
-}
+export * from "@langchain/community/embeddings/hf_transformers";
diff --git a/langchain/src/embeddings/llama_cpp.ts b/langchain/src/embeddings/llama_cpp.ts
index 51b9b3c3e007..3fcf55dda59a 100644
--- a/langchain/src/embeddings/llama_cpp.ts
+++ b/langchain/src/embeddings/llama_cpp.ts
@@ -1,103 +1 @@
-import { LlamaModel, LlamaContext } from "node-llama-cpp";
-import {
- LlamaBaseCppInputs,
- createLlamaModel,
- createLlamaContext,
-} from "../util/llama_cpp.js";
-import { Embeddings, EmbeddingsParams } from "./base.js";
-
-/**
- * Note that the modelPath is the only required parameter. For testing you
- * can set this in the environment variable `LLAMA_PATH`.
- */
-export interface LlamaCppEmbeddingsParams
- extends LlamaBaseCppInputs,
- EmbeddingsParams {}
-
-/**
- * @example
- * ```typescript
- * // Initialize LlamaCppEmbeddings with the path to the model file
- * const embeddings = new LlamaCppEmbeddings({
- * modelPath: "/Replace/with/path/to/your/model/gguf-llama2-q4_0.bin",
- * });
- *
- * // Embed a query string using the Llama embeddings
- * const res = embeddings.embedQuery("Hello Llama!");
- *
- * // Output the resulting embeddings
- * console.log(res);
- *
- * ```
- */
-export class LlamaCppEmbeddings extends Embeddings {
- _model: LlamaModel;
-
- _context: LlamaContext;
-
- constructor(inputs: LlamaCppEmbeddingsParams) {
- super(inputs);
- const _inputs = inputs;
- _inputs.embedding = true;
-
- this._model = createLlamaModel(_inputs);
- this._context = createLlamaContext(this._model, _inputs);
- }
-
- /**
- * Generates embeddings for an array of texts.
- * @param texts - An array of strings to generate embeddings for.
- * @returns A Promise that resolves to an array of embeddings.
- */
- async embedDocuments(texts: string[]): Promise {
- const tokensArray = [];
-
- for (const text of texts) {
- const encodings = await this.caller.call(
- () =>
- new Promise((resolve) => {
- resolve(this._context.encode(text));
- })
- );
- tokensArray.push(encodings);
- }
-
- const embeddings: number[][] = [];
-
- for (const tokens of tokensArray) {
- const embedArray: number[] = [];
-
- for (let i = 0; i < tokens.length; i += 1) {
- const nToken: number = +tokens[i];
- embedArray.push(nToken);
- }
-
- embeddings.push(embedArray);
- }
-
- return embeddings;
- }
-
- /**
- * Generates an embedding for a single text.
- * @param text - A string to generate an embedding for.
- * @returns A Promise that resolves to an array of numbers representing the embedding.
- */
- async embedQuery(text: string): Promise {
- const tokens: number[] = [];
-
- const encodings = await this.caller.call(
- () =>
- new Promise((resolve) => {
- resolve(this._context.encode(text));
- })
- );
-
- for (let i = 0; i < encodings.length; i += 1) {
- const token: number = +encodings[i];
- tokens.push(token);
- }
-
- return tokens;
- }
-}
+export * from "@langchain/community/embeddings/llama_cpp";
diff --git a/langchain/src/embeddings/minimax.ts b/langchain/src/embeddings/minimax.ts
index 80697e30f60a..8568bf09207e 100644
--- a/langchain/src/embeddings/minimax.ts
+++ b/langchain/src/embeddings/minimax.ts
@@ -1,222 +1 @@
-import { getEnvironmentVariable } from "../util/env.js";
-import { chunkArray } from "../util/chunk.js";
-import { Embeddings, EmbeddingsParams } from "./base.js";
-import { ConfigurationParameters } from "../chat_models/minimax.js";
-
-/**
- * Interface for MinimaxEmbeddings parameters. Extends EmbeddingsParams and
- * defines additional parameters specific to the MinimaxEmbeddings class.
- */
-export interface MinimaxEmbeddingsParams extends EmbeddingsParams {
- /** Model name to use */
- modelName: string;
-
- /**
- * API key to use when making requests. Defaults to the value of
- * `MINIMAX_GROUP_ID` environment variable.
- */
- minimaxGroupId?: string;
-
- /**
- * Secret key to use when making requests. Defaults to the value of
- * `MINIMAX_API_KEY` environment variable.
- */
- minimaxApiKey?: string;
-
- /**
- * The maximum number of documents to embed in a single request. This is
- * limited by the Minimax API to a maximum of 4096.
- */
- batchSize?: number;
-
- /**
- * Whether to strip new lines from the input text. This is recommended by
- * Minimax, but may not be suitable for all use cases.
- */
- stripNewLines?: boolean;
-
- /**
- * The target use-case after generating the vector.
- * When using embeddings, the vector of the target content is first generated through the db and stored in the vector database,
- * and then the vector of the retrieval text is generated through the query.
- * Note: For the parameters of the partial algorithm, we adopted a separate algorithm plan for query and db.
- * Therefore, for a paragraph of text, if it is to be used as a retrieval text, it should use the db,
- * and if it is used as a retrieval text, it should use the query.
- */
- type?: "db" | "query";
-}
-
-export interface CreateMinimaxEmbeddingRequest {
- /**
- * @type {string}
- * @memberof CreateMinimaxEmbeddingRequest
- */
- model: string;
-
- /**
- * Text to generate vector expectation
- * @type {CreateEmbeddingRequestInput}
- * @memberof CreateMinimaxEmbeddingRequest
- */
- texts: string[];
-
- /**
- * The target use-case after generating the vector. When using embeddings,
- * first generate the vector of the target content through the db and store it in the vector database,
- * and then generate the vector of the retrieval text through the query.
- * Note: For the parameter of the algorithm, we use the algorithm scheme of query and db separation,
- * so a text, if it is to be retrieved as a text, should use the db,
- * if it is used as a retrieval text, should use the query.
- * @type {string}
- * @memberof CreateMinimaxEmbeddingRequest
- */
- type: "db" | "query";
-}
-
-/**
- * Class for generating embeddings using the Minimax API. Extends the
- * Embeddings class and implements MinimaxEmbeddingsParams
- * @example
- * ```typescript
- * const embeddings = new MinimaxEmbeddings();
- *
- * // Embed a single query
- * const queryEmbedding = await embeddings.embedQuery("Hello world");
- * console.log(queryEmbedding);
- *
- * // Embed multiple documents
- * const documentsEmbedding = await embeddings.embedDocuments([
- * "Hello world",
- * "Bye bye",
- * ]);
- * console.log(documentsEmbedding);
- * ```
- */
-export class MinimaxEmbeddings
- extends Embeddings
- implements MinimaxEmbeddingsParams
-{
- modelName = "embo-01";
-
- batchSize = 512;
-
- stripNewLines = true;
-
- minimaxGroupId?: string;
-
- minimaxApiKey?: string;
-
- type: "db" | "query" = "db";
-
- apiUrl: string;
-
- basePath?: string = "https://api.minimax.chat/v1";
-
- headers?: Record;
-
- constructor(
- fields?: Partial & {
- configuration?: ConfigurationParameters;
- }
- ) {
- const fieldsWithDefaults = { maxConcurrency: 2, ...fields };
- super(fieldsWithDefaults);
-
- this.minimaxGroupId =
- fields?.minimaxGroupId ?? getEnvironmentVariable("MINIMAX_GROUP_ID");
- if (!this.minimaxGroupId) {
- throw new Error("Minimax GroupID not found");
- }
-
- this.minimaxApiKey =
- fields?.minimaxApiKey ?? getEnvironmentVariable("MINIMAX_API_KEY");
-
- if (!this.minimaxApiKey) {
- throw new Error("Minimax ApiKey not found");
- }
-
- this.modelName = fieldsWithDefaults?.modelName ?? this.modelName;
- this.batchSize = fieldsWithDefaults?.batchSize ?? this.batchSize;
- this.type = fieldsWithDefaults?.type ?? this.type;
- this.stripNewLines =
- fieldsWithDefaults?.stripNewLines ?? this.stripNewLines;
- this.basePath = fields?.configuration?.basePath ?? this.basePath;
- this.apiUrl = `${this.basePath}/embeddings`;
- this.headers = fields?.configuration?.headers ?? this.headers;
- }
-
- /**
- * Method to generate embeddings for an array of documents. Splits the
- * documents into batches and makes requests to the Minimax API to generate
- * embeddings.
- * @param texts Array of documents to generate embeddings for.
- * @returns Promise that resolves to a 2D array of embeddings for each document.
- */
- async embedDocuments(texts: string[]): Promise {
- const batches = chunkArray(
- this.stripNewLines ? texts.map((t) => t.replace(/\n/g, " ")) : texts,
- this.batchSize
- );
-
- const batchRequests = batches.map((batch) =>
- this.embeddingWithRetry({
- model: this.modelName,
- texts: batch,
- type: this.type,
- })
- );
- const batchResponses = await Promise.all(batchRequests);
-
- const embeddings: number[][] = [];
- for (let i = 0; i < batchResponses.length; i += 1) {
- const batch = batches[i];
- const { vectors: batchResponse } = batchResponses[i];
- for (let j = 0; j < batch.length; j += 1) {
- embeddings.push(batchResponse[j]);
- }
- }
- return embeddings;
- }
-
- /**
- * Method to generate an embedding for a single document. Calls the
- * embeddingWithRetry method with the document as the input.
- * @param text Document to generate an embedding for.
- * @returns Promise that resolves to an embedding for the document.
- */
- async embedQuery(text: string): Promise {
- const { vectors } = await this.embeddingWithRetry({
- model: this.modelName,
- texts: [this.stripNewLines ? text.replace(/\n/g, " ") : text],
- type: this.type,
- });
- return vectors[0];
- }
-
- /**
- * Private method to make a request to the Minimax API to generate
- * embeddings. Handles the retry logic and returns the response from the
- * API.
- * @param request Request to send to the Minimax API.
- * @returns Promise that resolves to the response from the API.
- */
- private async embeddingWithRetry(request: CreateMinimaxEmbeddingRequest) {
- const makeCompletionRequest = async () => {
- const url = `${this.apiUrl}?GroupId=${this.minimaxGroupId}`;
- const response = await fetch(url, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- Authorization: `Bearer ${this.minimaxApiKey}`,
- ...this.headers,
- },
- body: JSON.stringify(request),
- });
-
- const json = await response.json();
- return json;
- };
-
- return this.caller.call(makeCompletionRequest);
- }
-}
+export * from "@langchain/community/embeddings/minimax";
diff --git a/langchain/src/embeddings/ollama.ts b/langchain/src/embeddings/ollama.ts
index de9c77797dfe..9bd994c08dd9 100644
--- a/langchain/src/embeddings/ollama.ts
+++ b/langchain/src/embeddings/ollama.ts
@@ -1,148 +1 @@
-import { OllamaInput, OllamaRequestParams } from "../util/ollama.js";
-import { Embeddings, EmbeddingsParams } from "./base.js";
-
-type CamelCasedRequestOptions = Omit<
- OllamaInput,
- "baseUrl" | "model" | "format"
->;
-
-/**
- * Interface for OllamaEmbeddings parameters. Extends EmbeddingsParams and
- * defines additional parameters specific to the OllamaEmbeddings class.
- */
-interface OllamaEmbeddingsParams extends EmbeddingsParams {
- /** The Ollama model to use, e.g: "llama2:13b" */
- model?: string;
-
- /** Base URL of the Ollama server, defaults to "http://localhost:11434" */
- baseUrl?: string;
-
- /** Advanced Ollama API request parameters in camelCase, see
- * https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values
- * for details of the available parameters.
- */
- requestOptions?: CamelCasedRequestOptions;
-}
-
-export class OllamaEmbeddings extends Embeddings {
- model = "llama2";
-
- baseUrl = "http://localhost:11434";
-
- requestOptions?: OllamaRequestParams["options"];
-
- constructor(params?: OllamaEmbeddingsParams) {
- super(params || {});
-
- if (params?.model) {
- this.model = params.model;
- }
-
- if (params?.baseUrl) {
- this.baseUrl = params.baseUrl;
- }
-
- if (params?.requestOptions) {
- this.requestOptions = this._convertOptions(params.requestOptions);
- }
- }
-
- /** convert camelCased Ollama request options like "useMMap" to
- * the snake_cased equivalent which the ollama API actually uses.
- * Used only for consistency with the llms/Ollama and chatModels/Ollama classes
- */
- _convertOptions(requestOptions: CamelCasedRequestOptions) {
- const snakeCasedOptions: Record = {};
- const mapping: Record = {
- embeddingOnly: "embedding_only",
- f16KV: "f16_kv",
- frequencyPenalty: "frequency_penalty",
- logitsAll: "logits_all",
- lowVram: "low_vram",
- mainGpu: "main_gpu",
- mirostat: "mirostat",
- mirostatEta: "mirostat_eta",
- mirostatTau: "mirostat_tau",
- numBatch: "num_batch",
- numCtx: "num_ctx",
- numGpu: "num_gpu",
- numGqa: "num_gqa",
- numKeep: "num_keep",
- numThread: "num_thread",
- penalizeNewline: "penalize_newline",
- presencePenalty: "presence_penalty",
- repeatLastN: "repeat_last_n",
- repeatPenalty: "repeat_penalty",
- ropeFrequencyBase: "rope_frequency_base",
- ropeFrequencyScale: "rope_frequency_scale",
- temperature: "temperature",
- stop: "stop",
- tfsZ: "tfs_z",
- topK: "top_k",
- topP: "top_p",
- typicalP: "typical_p",
- useMLock: "use_mlock",
- useMMap: "use_mmap",
- vocabOnly: "vocab_only",
- };
-
- for (const [key, value] of Object.entries(requestOptions)) {
- const snakeCasedOption = mapping[key as keyof CamelCasedRequestOptions];
- if (snakeCasedOption) {
- snakeCasedOptions[snakeCasedOption] = value;
- }
- }
- return snakeCasedOptions;
- }
-
- async _request(prompt: string): Promise {
- const { model, baseUrl, requestOptions } = this;
-
- let formattedBaseUrl = baseUrl;
- if (formattedBaseUrl.startsWith("http://localhost:")) {
- // Node 18 has issues with resolving "localhost"
- // See https://github.com/node-fetch/node-fetch/issues/1624
- formattedBaseUrl = formattedBaseUrl.replace(
- "http://localhost:",
- "http://127.0.0.1:"
- );
- }
-
- const response = await fetch(`${formattedBaseUrl}/api/embeddings`, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({
- prompt,
- model,
- options: requestOptions,
- }),
- });
- if (!response.ok) {
- throw new Error(
- `Request to Ollama server failed: ${response.status} ${response.statusText}`
- );
- }
-
- const json = await response.json();
- return json.embedding;
- }
-
- async _embed(strings: string[]): Promise {
- const embeddings: number[][] = [];
-
- for await (const prompt of strings) {
- const embedding = await this.caller.call(() => this._request(prompt));
- embeddings.push(embedding);
- }
-
- return embeddings;
- }
-
- async embedDocuments(documents: string[]) {
- return this._embed(documents);
- }
-
- async embedQuery(document: string) {
- return (await this.embedDocuments([document]))[0];
- }
-}
+export * from "@langchain/community/embeddings/ollama";
diff --git a/langchain/src/embeddings/openai.ts b/langchain/src/embeddings/openai.ts
index 0cc726d03ca3..9c5af9d81995 100644
--- a/langchain/src/embeddings/openai.ts
+++ b/langchain/src/embeddings/openai.ts
@@ -1,269 +1,4 @@
-import { type ClientOptions, OpenAI as OpenAIClient } from "openai";
-import { getEnvironmentVariable } from "../util/env.js";
-import {
- AzureOpenAIInput,
- OpenAICoreRequestOptions,
- LegacyOpenAIInput,
-} from "../types/openai-types.js";
-import { chunkArray } from "../util/chunk.js";
-import { Embeddings, EmbeddingsParams } from "./base.js";
-import { getEndpoint, OpenAIEndpointConfig } from "../util/azure.js";
-import { wrapOpenAIClientError } from "../util/openai.js";
-
-/**
- * Interface for OpenAIEmbeddings parameters. Extends EmbeddingsParams and
- * defines additional parameters specific to the OpenAIEmbeddings class.
- */
-export interface OpenAIEmbeddingsParams extends EmbeddingsParams {
- /** Model name to use */
- modelName: string;
-
- /**
- * Timeout to use when making requests to OpenAI.
- */
- timeout?: number;
-
- /**
- * The maximum number of documents to embed in a single request. This is
- * limited by the OpenAI API to a maximum of 2048.
- */
- batchSize?: number;
-
- /**
- * Whether to strip new lines from the input text. This is recommended by
- * OpenAI, but may not be suitable for all use cases.
- */
- stripNewLines?: boolean;
-}
-
-/**
- * Class for generating embeddings using the OpenAI API. Extends the
- * Embeddings class and implements OpenAIEmbeddingsParams and
- * AzureOpenAIInput.
- * @example
- * ```typescript
- * // Embed a query using OpenAIEmbeddings to generate embeddings for a given text
- * const model = new OpenAIEmbeddings();
- * const res = await model.embedQuery(
- * "What would be a good company name for a company that makes colorful socks?",
- * );
- * console.log({ res });
- *
- * ```
- */
-export class OpenAIEmbeddings
- extends Embeddings
- implements OpenAIEmbeddingsParams, AzureOpenAIInput
-{
- modelName = "text-embedding-ada-002";
-
- batchSize = 512;
-
- stripNewLines = true;
-
- timeout?: number;
-
- azureOpenAIApiVersion?: string;
-
- azureOpenAIApiKey?: string;
-
- azureOpenAIApiInstanceName?: string;
-
- azureOpenAIApiDeploymentName?: string;
-
- azureOpenAIBasePath?: string;
-
- organization?: string;
-
- private client: OpenAIClient;
-
- private clientConfig: ClientOptions;
-
- constructor(
- fields?: Partial &
- Partial & {
- verbose?: boolean;
- openAIApiKey?: string;
- configuration?: ClientOptions;
- },
- configuration?: ClientOptions & LegacyOpenAIInput
- ) {
- const fieldsWithDefaults = { maxConcurrency: 2, ...fields };
-
- super(fieldsWithDefaults);
-
- let apiKey =
- fieldsWithDefaults?.openAIApiKey ??
- getEnvironmentVariable("OPENAI_API_KEY");
-
- const azureApiKey =
- fieldsWithDefaults?.azureOpenAIApiKey ??
- getEnvironmentVariable("AZURE_OPENAI_API_KEY");
- if (!azureApiKey && !apiKey) {
- throw new Error("OpenAI or Azure OpenAI API key not found");
- }
-
- const azureApiInstanceName =
- fieldsWithDefaults?.azureOpenAIApiInstanceName ??
- getEnvironmentVariable("AZURE_OPENAI_API_INSTANCE_NAME");
-
- const azureApiDeploymentName =
- (fieldsWithDefaults?.azureOpenAIApiEmbeddingsDeploymentName ||
- fieldsWithDefaults?.azureOpenAIApiDeploymentName) ??
- (getEnvironmentVariable("AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME") ||
- getEnvironmentVariable("AZURE_OPENAI_API_DEPLOYMENT_NAME"));
-
- const azureApiVersion =
- fieldsWithDefaults?.azureOpenAIApiVersion ??
- getEnvironmentVariable("AZURE_OPENAI_API_VERSION");
-
- this.azureOpenAIBasePath =
- fieldsWithDefaults?.azureOpenAIBasePath ??
- getEnvironmentVariable("AZURE_OPENAI_BASE_PATH");
-
- this.organization =
- fieldsWithDefaults?.configuration?.organization ??
- getEnvironmentVariable("OPENAI_ORGANIZATION");
-
- this.modelName = fieldsWithDefaults?.modelName ?? this.modelName;
- this.batchSize =
- fieldsWithDefaults?.batchSize ?? (azureApiKey ? 1 : this.batchSize);
- this.stripNewLines =
- fieldsWithDefaults?.stripNewLines ?? this.stripNewLines;
- this.timeout = fieldsWithDefaults?.timeout;
-
- this.azureOpenAIApiVersion = azureApiVersion;
- this.azureOpenAIApiKey = azureApiKey;
- this.azureOpenAIApiInstanceName = azureApiInstanceName;
- this.azureOpenAIApiDeploymentName = azureApiDeploymentName;
-
- if (this.azureOpenAIApiKey) {
- if (!this.azureOpenAIApiInstanceName && !this.azureOpenAIBasePath) {
- throw new Error("Azure OpenAI API instance name not found");
- }
- if (!this.azureOpenAIApiDeploymentName) {
- throw new Error("Azure OpenAI API deployment name not found");
- }
- if (!this.azureOpenAIApiVersion) {
- throw new Error("Azure OpenAI API version not found");
- }
- apiKey = apiKey ?? "";
- }
-
- this.clientConfig = {
- apiKey,
- organization: this.organization,
- baseURL: configuration?.basePath,
- dangerouslyAllowBrowser: true,
- defaultHeaders: configuration?.baseOptions?.headers,
- defaultQuery: configuration?.baseOptions?.params,
- ...configuration,
- ...fields?.configuration,
- };
- }
-
- /**
- * Method to generate embeddings for an array of documents. Splits the
- * documents into batches and makes requests to the OpenAI API to generate
- * embeddings.
- * @param texts Array of documents to generate embeddings for.
- * @returns Promise that resolves to a 2D array of embeddings for each document.
- */
- async embedDocuments(texts: string[]): Promise {
- const batches = chunkArray(
- this.stripNewLines ? texts.map((t) => t.replace(/\n/g, " ")) : texts,
- this.batchSize
- );
-
- const batchRequests = batches.map((batch) =>
- this.embeddingWithRetry({
- model: this.modelName,
- input: batch,
- })
- );
- const batchResponses = await Promise.all(batchRequests);
-
- const embeddings: number[][] = [];
- for (let i = 0; i < batchResponses.length; i += 1) {
- const batch = batches[i];
- const { data: batchResponse } = batchResponses[i];
- for (let j = 0; j < batch.length; j += 1) {
- embeddings.push(batchResponse[j].embedding);
- }
- }
- return embeddings;
- }
-
- /**
- * Method to generate an embedding for a single document. Calls the
- * embeddingWithRetry method with the document as the input.
- * @param text Document to generate an embedding for.
- * @returns Promise that resolves to an embedding for the document.
- */
- async embedQuery(text: string): Promise {
- const { data } = await this.embeddingWithRetry({
- model: this.modelName,
- input: this.stripNewLines ? text.replace(/\n/g, " ") : text,
- });
- return data[0].embedding;
- }
-
- /**
- * Private method to make a request to the OpenAI API to generate
- * embeddings. Handles the retry logic and returns the response from the
- * API.
- * @param request Request to send to the OpenAI API.
- * @returns Promise that resolves to the response from the API.
- */
- private async embeddingWithRetry(
- request: OpenAIClient.EmbeddingCreateParams
- ) {
- if (!this.client) {
- const openAIEndpointConfig: OpenAIEndpointConfig = {
- azureOpenAIApiDeploymentName: this.azureOpenAIApiDeploymentName,
- azureOpenAIApiInstanceName: this.azureOpenAIApiInstanceName,
- azureOpenAIApiKey: this.azureOpenAIApiKey,
- azureOpenAIBasePath: this.azureOpenAIBasePath,
- baseURL: this.clientConfig.baseURL,
- };
-
- const endpoint = getEndpoint(openAIEndpointConfig);
-
- const params = {
- ...this.clientConfig,
- baseURL: endpoint,
- timeout: this.timeout,
- maxRetries: 0,
- };
-
- if (!params.baseURL) {
- delete params.baseURL;
- }
-
- this.client = new OpenAIClient(params);
- }
- const requestOptions: OpenAICoreRequestOptions = {};
- if (this.azureOpenAIApiKey) {
- requestOptions.headers = {
- "api-key": this.azureOpenAIApiKey,
- ...requestOptions.headers,
- };
- requestOptions.query = {
- "api-version": this.azureOpenAIApiVersion,
- ...requestOptions.query,
- };
- }
- return this.caller.call(async () => {
- try {
- const res = await this.client.embeddings.create(
- request,
- requestOptions
- );
- return res;
- } catch (e) {
- const error = wrapOpenAIClientError(e);
- throw error;
- }
- });
- }
-}
+export {
+ type OpenAIEmbeddingsParams,
+ OpenAIEmbeddings,
+} from "@langchain/openai";
diff --git a/langchain/src/embeddings/tensorflow.ts b/langchain/src/embeddings/tensorflow.ts
index 1fc198ccdb8f..cd09a7c82cf5 100644
--- a/langchain/src/embeddings/tensorflow.ts
+++ b/langchain/src/embeddings/tensorflow.ts
@@ -1,91 +1 @@
-import { load } from "@tensorflow-models/universal-sentence-encoder";
-import * as tf from "@tensorflow/tfjs-core";
-
-import { Embeddings, EmbeddingsParams } from "./base.js";
-
-/**
- * Interface that extends EmbeddingsParams and defines additional
- * parameters specific to the TensorFlowEmbeddings class.
- */
-export interface TensorFlowEmbeddingsParams extends EmbeddingsParams {}
-
-/**
- * Class that extends the Embeddings class and provides methods for
- * generating embeddings using the Universal Sentence Encoder model from
- * TensorFlow.js.
- * @example
- * ```typescript
- * const embeddings = new TensorFlowEmbeddings();
- * const store = new MemoryVectorStore(embeddings);
- *
- * const documents = [
- * "A document",
- * "Some other piece of text",
- * "One more",
- * "And another",
- * ];
- *
- * await store.addDocuments(
- * documents.map((pageContent) => new Document({ pageContent }))
- * );
- * ```
- */
-export class TensorFlowEmbeddings extends Embeddings {
- constructor(fields?: TensorFlowEmbeddingsParams) {
- super(fields ?? {});
-
- try {
- tf.backend();
- } catch (e) {
- throw new Error("No TensorFlow backend found, see instructions at ...");
- }
- }
-
- _cached: ReturnType;
-
- /**
- * Private method that loads the Universal Sentence Encoder model if it
- * hasn't been loaded already. It returns a promise that resolves to the
- * loaded model.
- * @returns Promise that resolves to the loaded Universal Sentence Encoder model.
- */
- private async load() {
- if (this._cached === undefined) {
- this._cached = load();
- }
- return this._cached;
- }
-
- private _embed(texts: string[]) {
- return this.caller.call(async () => {
- const model = await this.load();
- return model.embed(texts);
- });
- }
-
- /**
- * Method that takes a document as input and returns a promise that
- * resolves to an embedding for the document. It calls the _embed method
- * with the document as the input and processes the result to return a
- * single embedding.
- * @param document Document to generate an embedding for.
- * @returns Promise that resolves to an embedding for the input document.
- */
- embedQuery(document: string): Promise {
- return this._embed([document])
- .then((embeddings) => embeddings.array())
- .then((embeddings) => embeddings[0]);
- }
-
- /**
- * Method that takes an array of documents as input and returns a promise
- * that resolves to a 2D array of embeddings for each document. It calls
- * the _embed method with the documents as the input and processes the
- * result to return the embeddings.
- * @param documents Array of documents to generate embeddings for.
- * @returns Promise that resolves to a 2D array of embeddings for each input document.
- */
- embedDocuments(documents: string[]): Promise {
- return this._embed(documents).then((embeddings) => embeddings.array());
- }
-}
+export * from "@langchain/community/embeddings/tensorflow";
diff --git a/langchain/src/embeddings/voyage.ts b/langchain/src/embeddings/voyage.ts
index 6b4d03c7e210..ea725613d118 100644
--- a/langchain/src/embeddings/voyage.ts
+++ b/langchain/src/embeddings/voyage.ts
@@ -1,152 +1 @@
-import { chunkArray } from "../util/chunk.js";
-import { getEnvironmentVariable } from "../util/env.js";
-import { Embeddings, EmbeddingsParams } from "./base.js";
-
-/**
- * Interface that extends EmbeddingsParams and defines additional
- * parameters specific to the VoyageEmbeddings class.
- */
-export interface VoyageEmbeddingsParams extends EmbeddingsParams {
- modelName: string;
-
- /**
- * The maximum number of documents to embed in a single request. This is
- * limited by the Voyage AI API to a maximum of 8.
- */
- batchSize?: number;
-}
-
-/**
- * Interface for the request body to generate embeddings.
- */
-export interface CreateVoyageEmbeddingRequest {
- /**
- * @type {string}
- * @memberof CreateVoyageEmbeddingRequest
- */
- model: string;
-
- /**
- * Text to generate vector expectation
- * @type {CreateEmbeddingRequestInput}
- * @memberof CreateVoyageEmbeddingRequest
- */
- input: string | string[];
-}
-
-/**
- * A class for generating embeddings using the Voyage AI API.
- */
-export class VoyageEmbeddings
- extends Embeddings
- implements VoyageEmbeddingsParams
-{
- modelName = "voyage-01";
-
- batchSize = 8;
-
- private apiKey: string;
-
- basePath?: string = "https://api.voyageai.com/v1";
-
- apiUrl: string;
-
- headers?: Record;
-
- /**
- * Constructor for the VoyageEmbeddings class.
- * @param fields - An optional object with properties to configure the instance.
- */
- constructor(
- fields?: Partial & {
- verbose?: boolean;
- apiKey?: string;
- }
- ) {
- const fieldsWithDefaults = { ...fields };
-
- super(fieldsWithDefaults);
-
- const apiKey =
- fieldsWithDefaults?.apiKey || getEnvironmentVariable("VOYAGEAI_API_KEY");
-
- if (!apiKey) {
- throw new Error("Voyage AI API key not found");
- }
-
- this.modelName = fieldsWithDefaults?.modelName ?? this.modelName;
- this.batchSize = fieldsWithDefaults?.batchSize ?? this.batchSize;
- this.apiKey = apiKey;
- this.apiUrl = `${this.basePath}/embeddings`;
- }
-
- /**
- * Generates embeddings for an array of texts.
- * @param texts - An array of strings to generate embeddings for.
- * @returns A Promise that resolves to an array of embeddings.
- */
- async embedDocuments(texts: string[]): Promise {
- const batches = chunkArray(texts, this.batchSize);
-
- const batchRequests = batches.map((batch) =>
- this.embeddingWithRetry({
- model: this.modelName,
- input: batch,
- })
- );
-
- const batchResponses = await Promise.all(batchRequests);
-
- const embeddings: number[][] = [];
-
- for (let i = 0; i < batchResponses.length; i += 1) {
- const batch = batches[i];
- const { data: batchResponse } = batchResponses[i];
- for (let j = 0; j < batch.length; j += 1) {
- embeddings.push(batchResponse[j].embedding);
- }
- }
-
- return embeddings;
- }
-
- /**
- * Generates an embedding for a single text.
- * @param text - A string to generate an embedding for.
- * @returns A Promise that resolves to an array of numbers representing the embedding.
- */
- async embedQuery(text: string): Promise {
- const { data } = await this.embeddingWithRetry({
- model: this.modelName,
- input: text,
- });
-
- return data[0].embedding;
- }
-
- /**
- * Makes a request to the Voyage AI API to generate embeddings for an array of texts.
- * @param request - An object with properties to configure the request.
- * @returns A Promise that resolves to the response from the Voyage AI API.
- */
-
- private async embeddingWithRetry(request: CreateVoyageEmbeddingRequest) {
- const makeCompletionRequest = async () => {
- const url = `${this.apiUrl}`;
- const response = await fetch(url, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- Authorization: `Bearer ${this.apiKey}`,
- ...this.headers,
- },
- body: JSON.stringify(request),
- });
-
- const json = await response.json();
- return json;
- };
-
- return this.caller.call(makeCompletionRequest);
- }
-}
+export * from "@langchain/community/embeddings/voyage";
diff --git a/langchain/src/experimental/openai_assistant/index.ts b/langchain/src/experimental/openai_assistant/index.ts
index 2e39836f30f3..248ff9407977 100644
--- a/langchain/src/experimental/openai_assistant/index.ts
+++ b/langchain/src/experimental/openai_assistant/index.ts
@@ -1,4 +1,4 @@
-import { type ClientOptions, OpenAI as OpenAIClient } from "openai";
+import { type ClientOptions, OpenAIClient } from "@langchain/openai";
import { Runnable } from "../../schema/runnable/base.js";
import { sleep } from "../../util/time.js";
import type { RunnableConfig } from "../../schema/runnable/config.js";
diff --git a/langchain/src/experimental/openai_assistant/schema.ts b/langchain/src/experimental/openai_assistant/schema.ts
index 10d4ce2658f4..a74ca1fce69f 100644
--- a/langchain/src/experimental/openai_assistant/schema.ts
+++ b/langchain/src/experimental/openai_assistant/schema.ts
@@ -1,4 +1,4 @@
-import type { OpenAI as OpenAIClient } from "openai";
+import type { OpenAIClient } from "@langchain/openai";
import type { AgentFinish, AgentAction } from "../../schema/index.js";
export type OpenAIAssistantFinish = AgentFinish & {
diff --git a/langchain/src/experimental/openai_assistant/tests/openai_assistant.int.test.ts b/langchain/src/experimental/openai_assistant/tests/openai_assistant.int.test.ts
index d1dac7daed6a..27d86403fc7e 100644
--- a/langchain/src/experimental/openai_assistant/tests/openai_assistant.int.test.ts
+++ b/langchain/src/experimental/openai_assistant/tests/openai_assistant.int.test.ts
@@ -2,7 +2,7 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { z } from "zod";
-import { OpenAI as OpenAIClient } from "openai";
+import { OpenAIClient } from "@langchain/openai";
import { AgentExecutor } from "../../../agents/executor.js";
import { StructuredTool } from "../../../tools/base.js";
import { OpenAIAssistantRunnable } from "../index.js";
diff --git a/langchain/src/experimental/openai_files/index.ts b/langchain/src/experimental/openai_files/index.ts
index 6522e906fd29..62f35dadf438 100644
--- a/langchain/src/experimental/openai_files/index.ts
+++ b/langchain/src/experimental/openai_files/index.ts
@@ -1,4 +1,4 @@
-import { OpenAI as OpenAIClient, type ClientOptions } from "openai";
+import { OpenAIClient, type ClientOptions } from "@langchain/openai";
import { Serializable } from "../../load/serializable.js";
export type OpenAIFilesInput = {
diff --git a/langchain/src/graphs/neo4j_graph.ts b/langchain/src/graphs/neo4j_graph.ts
index c404e7e3b2ad..99cc0011f46a 100644
--- a/langchain/src/graphs/neo4j_graph.ts
+++ b/langchain/src/graphs/neo4j_graph.ts
@@ -1,286 +1 @@
-import neo4j, { Neo4jError } from "neo4j-driver";
-
-interface Neo4jGraphConfig {
- url: string;
- username: string;
- password: string;
- database?: string;
-}
-
-interface StructuredSchema {
- nodeProps: { [key: NodeType["labels"]]: NodeType["properties"] };
- relProps: { [key: RelType["type"]]: RelType["properties"] };
- relationships: PathType[];
-}
-
-type NodeType = {
- labels: string;
- properties: { property: string; type: string }[];
-};
-type RelType = {
- type: string;
- properties: { property: string; type: string }[];
-};
-type PathType = { start: string; type: string; end: string };
-
-/**
- * @security *Security note*: Make sure that the database connection uses credentials
- * that are narrowly-scoped to only include necessary permissions.
- * Failure to do so may result in data corruption or loss, since the calling
- * code may attempt commands that would result in deletion, mutation
- * of data if appropriately prompted or reading sensitive data if such
- * data is present in the database.
- * The best way to guard against such negative outcomes is to (as appropriate)
- * limit the permissions granted to the credentials used with this tool.
- * For example, creating read only users for the database is a good way to
- * ensure that the calling code cannot mutate or delete data.
- *
- * @link See https://js.langchain.com/docs/security for more information.
- */
-export class Neo4jGraph {
- private driver: neo4j.Driver;
-
- private database: string;
-
- private schema = "";
-
- private structuredSchema: StructuredSchema = {
- nodeProps: {},
- relProps: {},
- relationships: [],
- };
-
- constructor({
- url,
- username,
- password,
- database = "neo4j",
- }: Neo4jGraphConfig) {
- try {
- this.driver = neo4j.driver(url, neo4j.auth.basic(username, password));
- this.database = database;
- } catch (error) {
- throw new Error(
- "Could not create a Neo4j driver instance. Please check the connection details."
- );
- }
- }
-
- static async initialize(config: Neo4jGraphConfig): Promise {
- const graph = new Neo4jGraph(config);
-
- try {
- await graph.verifyConnectivity();
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- } catch (error: any) {
- console.log("Failed to verify connection.");
- }
-
- try {
- await graph.refreshSchema();
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- } catch (error: any) {
- const message = [
- "Could not use APOC procedures.",
- "Please ensure the APOC plugin is installed in Neo4j and that",
- "'apoc.meta.data()' is allowed in Neo4j configuration",
- ].join("\n");
-
- throw new Error(message);
- } finally {
- console.log("Schema refreshed successfully.");
- }
-
- return graph;
- }
-
- getSchema(): string {
- return this.schema;
- }
-
- getStructuredSchema() {
- return this.structuredSchema;
- }
-
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- async query(query: string, params: any = {}): Promise {
- try {
- const result = await this.driver.executeQuery(query, params, {
- database: this.database,
- });
- return toObjects(result.records);
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- } catch (error: any) {
- if (
- // eslint-disable-next-line
- error instanceof Neo4jError &&
- error.code === "Neo.ClientError.Procedure.ProcedureNotFound"
- ) {
- throw new Error("Procedure not found in Neo4j.");
- }
- }
- return undefined;
- }
-
- async verifyConnectivity() {
- await this.driver.verifyAuthentication();
- }
-
- async refreshSchema() {
- const nodePropertiesQuery = `
- CALL apoc.meta.data()
- YIELD label, other, elementType, type, property
- WHERE NOT type = "RELATIONSHIP" AND elementType = "node"
- WITH label AS nodeLabels, collect({property:property, type:type}) AS properties
- RETURN {labels: nodeLabels, properties: properties} AS output
- `;
-
- const relPropertiesQuery = `
- CALL apoc.meta.data()
- YIELD label, other, elementType, type, property
- WHERE NOT type = "RELATIONSHIP" AND elementType = "relationship"
- WITH label AS nodeLabels, collect({property:property, type:type}) AS properties
- RETURN {type: nodeLabels, properties: properties} AS output
- `;
-
- const relQuery = `
- CALL apoc.meta.data()
- YIELD label, other, elementType, type, property
- WHERE type = "RELATIONSHIP" AND elementType = "node"
- UNWIND other AS other_node
- RETURN {start: label, type: property, end: toString(other_node)} AS output
- `;
-
- // Assuming query method is defined and returns a Promise
- const nodeProperties: NodeType[] | undefined = (
- await this.query(nodePropertiesQuery)
- )?.map((el: { output: NodeType }) => el.output);
-
- const relationshipsProperties: RelType[] | undefined = (
- await this.query(relPropertiesQuery)
- )?.map((el: { output: RelType }) => el.output);
-
- const relationships: PathType[] | undefined = (
- await this.query(relQuery)
- )?.map((el: { output: PathType }) => el.output);
-
- // Structured schema similar to Python's dictionary comprehension
- this.structuredSchema = {
- nodeProps: Object.fromEntries(
- nodeProperties?.map((el) => [el.labels, el.properties]) || []
- ),
- relProps: Object.fromEntries(
- relationshipsProperties?.map((el) => [el.type, el.properties]) || []
- ),
- relationships: relationships || [],
- };
-
- // Format node properties
- const formattedNodeProps = nodeProperties?.map((el) => {
- const propsStr = el.properties
- .map((prop) => `${prop.property}: ${prop.type}`)
- .join(", ");
- return `${el.labels} {${propsStr}}`;
- });
-
- // Format relationship properties
- const formattedRelProps = relationshipsProperties?.map((el) => {
- const propsStr = el.properties
- .map((prop) => `${prop.property}: ${prop.type}`)
- .join(", ");
- return `${el.type} {${propsStr}}`;
- });
-
- // Format relationships
- const formattedRels = relationships?.map(
- (el) => `(:${el.start})-[:${el.type}]->(:${el.end})`
- );
-
- // Combine all formatted elements into a single string
- this.schema = [
- "Node properties are the following:",
- formattedNodeProps?.join(", "),
- "Relationship properties are the following:",
- formattedRelProps?.join(", "),
- "The relationships are the following:",
- formattedRels?.join(", "),
- ].join("\n");
- }
-
- async close() {
- await this.driver.close();
- }
-}
-
-function toObjects(records: neo4j.Record[]) {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const recordValues: Record[] = records.map((record) => {
- const rObj = record.toObject();
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const out: { [key: string]: any } = {};
- Object.keys(rObj).forEach((key) => {
- out[key] = itemIntToString(rObj[key]);
- });
- return out;
- });
- return recordValues;
-}
-
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-function itemIntToString(item: any): any {
- if (neo4j.isInt(item)) return item.toString();
- if (Array.isArray(item)) return item.map((ii) => itemIntToString(ii));
- if (["number", "string", "boolean"].indexOf(typeof item) !== -1) return item;
- if (item === null) return item;
- if (typeof item === "object") return objIntToString(item);
-}
-
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-function objIntToString(obj: any) {
- const entry = extractFromNeoObjects(obj);
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- let newObj: any = null;
- if (Array.isArray(entry)) {
- newObj = entry.map((item) => itemIntToString(item));
- } else if (entry !== null && typeof entry === "object") {
- newObj = {};
- Object.keys(entry).forEach((key) => {
- newObj[key] = itemIntToString(entry[key]);
- });
- }
- return newObj;
-}
-
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-function extractFromNeoObjects(obj: any) {
- if (
- // eslint-disable-next-line
- obj instanceof (neo4j.types.Node as any) ||
- // eslint-disable-next-line
- obj instanceof (neo4j.types.Relationship as any)
- ) {
- return obj.properties;
- // eslint-disable-next-line
- } else if (obj instanceof (neo4j.types.Path as any)) {
- // eslint-disable-next-line
- return [].concat.apply([], extractPathForRows(obj));
- }
- return obj;
-}
-
-const extractPathForRows = (path: neo4j.Path) => {
- let { segments } = path;
- // Zero length path. No relationship, end === start
- if (!Array.isArray(path.segments) || path.segments.length < 1) {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- segments = [{ ...path, end: null } as any];
- }
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- return segments.map((segment: any) =>
- [
- objIntToString(segment.start),
- objIntToString(segment.relationship),
- objIntToString(segment.end),
- ].filter((part) => part !== null)
- );
-};
+export * from "@langchain/community/graphs/neo4j_graph";
diff --git a/langchain/src/graphs/tests/neo4j_graph.int.test.ts b/langchain/src/graphs/tests/neo4j_graph.int.test.ts
deleted file mode 100644
index 3b47800fc323..000000000000
--- a/langchain/src/graphs/tests/neo4j_graph.int.test.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-/* eslint-disable no-process-env */
-
-import { test } from "@jest/globals";
-import { Neo4jGraph } from "../neo4j_graph.js";
-
-describe.skip("Neo4j Graph Tests", () => {
- const url = process.env.NEO4J_URI as string;
- const username = process.env.NEO4J_USERNAME as string;
- const password = process.env.NEO4J_PASSWORD as string;
- let graph: Neo4jGraph;
-
- beforeEach(async () => {
- graph = await Neo4jGraph.initialize({ url, username, password });
- });
- afterEach(async () => {
- await graph.close();
- });
-
- test("Schema generation works correctly", async () => {
- expect(url).toBeDefined();
- expect(username).toBeDefined();
- expect(password).toBeDefined();
-
- // Clear the database
- await graph.query("MATCH (n) DETACH DELETE n");
-
- await graph.query(
- "CREATE (a:Actor {name:'Bruce Willis'})" +
- "-[:ACTED_IN {roles: ['Butch Coolidge']}]->(:Movie {title: 'Pulp Fiction'})"
- );
-
- await graph.refreshSchema();
- console.log(graph.getSchema());
-
- // expect(graph.getSchema()).toMatchInlineSnapshot(`
- // "Node properties are the following:
- // Actor {name: STRING}, Movie {title: STRING}
- // Relationship properties are the following:
- // ACTED_IN {roles: LIST}
- // The relationships are the following:
- // (:Actor)-[:ACTED_IN]->(:Movie)"
- // `);
- });
-
- test("Test that Neo4j database is correctly instantiated and connected", async () => {
- expect(url).toBeDefined();
- expect(username).toBeDefined();
- expect(password).toBeDefined();
-
- // Integers are casted to strings in the output
- const expectedOutput = [{ output: { str: "test", int: "1" } }];
- const res = await graph.query('RETURN {str: "test", int: 1} AS output');
- await graph.close();
- expect(res).toEqual(expectedOutput);
- });
-});
diff --git a/langchain/src/llms/ai21.ts b/langchain/src/llms/ai21.ts
index 66d63b97abc3..d68f4b637a87 100644
--- a/langchain/src/llms/ai21.ts
+++ b/langchain/src/llms/ai21.ts
@@ -1,199 +1 @@
-import { LLM, BaseLLMParams } from "./base.js";
-import { getEnvironmentVariable } from "../util/env.js";
-
-/**
- * Type definition for AI21 penalty data.
- */
-export type AI21PenaltyData = {
- scale: number;
- applyToWhitespaces: boolean;
- applyToPunctuations: boolean;
- applyToNumbers: boolean;
- applyToStopwords: boolean;
- applyToEmojis: boolean;
-};
-
-/**
- * Interface for AI21 input parameters.
- */
-export interface AI21Input extends BaseLLMParams {
- ai21ApiKey?: string;
- model?: string;
- temperature?: number;
- minTokens?: number;
- maxTokens?: number;
- topP?: number;
- presencePenalty?: AI21PenaltyData;
- countPenalty?: AI21PenaltyData;
- frequencyPenalty?: AI21PenaltyData;
- numResults?: number;
- logitBias?: Record;
- stop?: string[];
- baseUrl?: string;
-}
-
-/**
- * Class representing the AI21 language model. It extends the LLM (Large
- * Language Model) class, providing a standard interface for interacting
- * with the AI21 language model.
- */
-export class AI21 extends LLM implements AI21Input {
- model = "j2-jumbo-instruct";
-
- temperature = 0.7;
-
- maxTokens = 1024;
-
- minTokens = 0;
-
- topP = 1;
-
- presencePenalty = AI21.getDefaultAI21PenaltyData();
-
- countPenalty = AI21.getDefaultAI21PenaltyData();
-
- frequencyPenalty = AI21.getDefaultAI21PenaltyData();
-
- numResults = 1;
-
- logitBias?: Record;
-
- ai21ApiKey?: string;
-
- stop?: string[];
-
- baseUrl?: string;
-
- constructor(fields?: AI21Input) {
- super(fields ?? {});
-
- this.model = fields?.model ?? this.model;
- this.temperature = fields?.temperature ?? this.temperature;
- this.maxTokens = fields?.maxTokens ?? this.maxTokens;
- this.minTokens = fields?.minTokens ?? this.minTokens;
- this.topP = fields?.topP ?? this.topP;
- this.presencePenalty = fields?.presencePenalty ?? this.presencePenalty;
- this.countPenalty = fields?.countPenalty ?? this.countPenalty;
- this.frequencyPenalty = fields?.frequencyPenalty ?? this.frequencyPenalty;
- this.numResults = fields?.numResults ?? this.numResults;
- this.logitBias = fields?.logitBias;
- this.ai21ApiKey =
- fields?.ai21ApiKey ?? getEnvironmentVariable("AI21_API_KEY");
- this.stop = fields?.stop;
- this.baseUrl = fields?.baseUrl;
- }
-
- /**
- * Method to validate the environment. It checks if the AI21 API key is
- * set. If not, it throws an error.
- */
- validateEnvironment() {
- if (!this.ai21ApiKey) {
- throw new Error(
- `No AI21 API key found. Please set it as "AI21_API_KEY" in your environment variables.`
- );
- }
- }
-
- /**
- * Static method to get the default penalty data for AI21.
- * @returns AI21PenaltyData
- */
- static getDefaultAI21PenaltyData(): AI21PenaltyData {
- return {
- scale: 0,
- applyToWhitespaces: true,
- applyToPunctuations: true,
- applyToNumbers: true,
- applyToStopwords: true,
- applyToEmojis: true,
- };
- }
-
- /** Get the type of LLM. */
- _llmType() {
- return "ai21";
- }
-
- /** Get the default parameters for calling AI21 API. */
- get defaultParams() {
- return {
- temperature: this.temperature,
- maxTokens: this.maxTokens,
- minTokens: this.minTokens,
- topP: this.topP,
- presencePenalty: this.presencePenalty,
- countPenalty: this.countPenalty,
- frequencyPenalty: this.frequencyPenalty,
- numResults: this.numResults,
- logitBias: this.logitBias,
- };
- }
-
- /** Get the identifying parameters for this LLM. */
- get identifyingParams() {
- return { ...this.defaultParams, model: this.model };
- }
-
- /** Call out to AI21's complete endpoint.
- Args:
- prompt: The prompt to pass into the model.
- stop: Optional list of stop words to use when generating.
-
- Returns:
- The string generated by the model.
-
- Example:
- let response = ai21._call("Tell me a joke.");
- */
- async _call(
- prompt: string,
- options: this["ParsedCallOptions"]
- ): Promise {
- let stop = options?.stop;
- this.validateEnvironment();
- if (this.stop && stop && this.stop.length > 0 && stop.length > 0) {
- throw new Error("`stop` found in both the input and default params.");
- }
- stop = this.stop ?? stop ?? [];
-
- const baseUrl =
- this.baseUrl ?? this.model === "j1-grande-instruct"
- ? "https://api.ai21.com/studio/v1/experimental"
- : "https://api.ai21.com/studio/v1";
-
- const url = `${baseUrl}/${this.model}/complete`;
- const headers = {
- Authorization: `Bearer ${this.ai21ApiKey}`,
- "Content-Type": "application/json",
- };
- const data = { prompt, stopSequences: stop, ...this.defaultParams };
- const responseData = await this.caller.callWithOptions({}, async () => {
- const response = await fetch(url, {
- method: "POST",
- headers,
- body: JSON.stringify(data),
- signal: options.signal,
- });
- if (!response.ok) {
- const error = new Error(
- `AI21 call failed with status code ${response.status}`
- );
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- (error as any).response = response;
- throw error;
- }
- return response.json();
- });
-
- if (
- !responseData.completions ||
- responseData.completions.length === 0 ||
- !responseData.completions[0].data
- ) {
- throw new Error("No completions found in response");
- }
-
- return responseData.completions[0].data.text ?? "";
- }
-}
+export * from "@langchain/community/llms/ai21";
diff --git a/langchain/src/llms/aleph_alpha.ts b/langchain/src/llms/aleph_alpha.ts
index 0e8968327073..1d0c12be8e26 100644
--- a/langchain/src/llms/aleph_alpha.ts
+++ b/langchain/src/llms/aleph_alpha.ts
@@ -1,298 +1 @@
-import { LLM, BaseLLMParams } from "./base.js";
-import { getEnvironmentVariable } from "../util/env.js";
-
-/**
- * Interface for the input parameters specific to the Aleph Alpha LLM.
- */
-export interface AlephAlphaInput extends BaseLLMParams {
- model: string;
- maximum_tokens: number;
- minimum_tokens?: number;
- echo?: boolean;
- temperature?: number;
- top_k?: number;
- top_p?: number;
- presence_penalty?: number;
- frequency_penalty?: number;
- sequence_penalty?: number;
- sequence_penalty_min_length?: number;
- repetition_penalties_include_prompt?: boolean;
- repetition_penalties_include_completion?: boolean;
- use_multiplicative_presence_penalty?: boolean;
- use_multiplicative_frequency_penalty?: boolean;
- use_multiplicative_sequence_penalty?: boolean;
- penalty_bias?: string;
- penalty_exceptions?: string[];
- penalty_exceptions_include_stop_sequences?: boolean;
- best_of?: number;
- n?: number;
- logit_bias?: object;
- log_probs?: number;
- tokens?: boolean;
- raw_completion: boolean;
- disable_optimizations?: boolean;
- completion_bias_inclusion?: string[];
- completion_bias_inclusion_first_token_only: boolean;
- completion_bias_exclusion?: string[];
- completion_bias_exclusion_first_token_only: boolean;
- contextual_control_threshold?: number;
- control_log_additive: boolean;
- stop?: string[];
- aleph_alpha_api_key?: string;
- base_url: string;
-}
-
-/**
- * Specific implementation of a Large Language Model (LLM) designed to
- * interact with the Aleph Alpha API. It extends the base LLM class and
- * includes a variety of parameters for customizing the behavior of the
- * Aleph Alpha model.
- */
-export class AlephAlpha extends LLM implements AlephAlphaInput {
- model = "luminous-base";
-
- maximum_tokens = 64;
-
- minimum_tokens = 0;
-
- echo: boolean;
-
- temperature = 0.0;
-
- top_k: number;
-
- top_p = 0.0;
-
- presence_penalty?: number;
-
- frequency_penalty?: number;
-
- sequence_penalty?: number;
-
- sequence_penalty_min_length?: number;
-
- repetition_penalties_include_prompt?: boolean;
-
- repetition_penalties_include_completion?: boolean;
-
- use_multiplicative_presence_penalty?: boolean;
-
- use_multiplicative_frequency_penalty?: boolean;
-
- use_multiplicative_sequence_penalty?: boolean;
-
- penalty_bias?: string;
-
- penalty_exceptions?: string[];
-
- penalty_exceptions_include_stop_sequences?: boolean;
-
- best_of?: number;
-
- n?: number;
-
- logit_bias?: object;
-
- log_probs?: number;
-
- tokens?: boolean;
-
- raw_completion: boolean;
-
- disable_optimizations?: boolean;
-
- completion_bias_inclusion?: string[];
-
- completion_bias_inclusion_first_token_only: boolean;
-
- completion_bias_exclusion?: string[];
-
- completion_bias_exclusion_first_token_only: boolean;
-
- contextual_control_threshold?: number;
-
- control_log_additive: boolean;
-
- aleph_alpha_api_key? = getEnvironmentVariable("ALEPH_ALPHA_API_KEY");
-
- stop?: string[];
-
- base_url = "https://api.aleph-alpha.com/complete";
-
- constructor(fields: Partial) {
- super(fields ?? {});
- this.model = fields?.model ?? this.model;
- this.temperature = fields?.temperature ?? this.temperature;
- this.maximum_tokens = fields?.maximum_tokens ?? this.maximum_tokens;
- this.minimum_tokens = fields?.minimum_tokens ?? this.minimum_tokens;
- this.top_k = fields?.top_k ?? this.top_k;
- this.top_p = fields?.top_p ?? this.top_p;
- this.presence_penalty = fields?.presence_penalty ?? this.presence_penalty;
- this.frequency_penalty =
- fields?.frequency_penalty ?? this.frequency_penalty;
- this.sequence_penalty = fields?.sequence_penalty ?? this.sequence_penalty;
- this.sequence_penalty_min_length =
- fields?.sequence_penalty_min_length ?? this.sequence_penalty_min_length;
- this.repetition_penalties_include_prompt =
- fields?.repetition_penalties_include_prompt ??
- this.repetition_penalties_include_prompt;
- this.repetition_penalties_include_completion =
- fields?.repetition_penalties_include_completion ??
- this.repetition_penalties_include_completion;
- this.use_multiplicative_presence_penalty =
- fields?.use_multiplicative_presence_penalty ??
- this.use_multiplicative_presence_penalty;
- this.use_multiplicative_frequency_penalty =
- fields?.use_multiplicative_frequency_penalty ??
- this.use_multiplicative_frequency_penalty;
- this.use_multiplicative_sequence_penalty =
- fields?.use_multiplicative_sequence_penalty ??
- this.use_multiplicative_sequence_penalty;
- this.penalty_bias = fields?.penalty_bias ?? this.penalty_bias;
- this.penalty_exceptions =
- fields?.penalty_exceptions ?? this.penalty_exceptions;
- this.penalty_exceptions_include_stop_sequences =
- fields?.penalty_exceptions_include_stop_sequences ??
- this.penalty_exceptions_include_stop_sequences;
- this.best_of = fields?.best_of ?? this.best_of;
- this.n = fields?.n ?? this.n;
- this.logit_bias = fields?.logit_bias ?? this.logit_bias;
- this.log_probs = fields?.log_probs ?? this.log_probs;
- this.tokens = fields?.tokens ?? this.tokens;
- this.raw_completion = fields?.raw_completion ?? this.raw_completion;
- this.disable_optimizations =
- fields?.disable_optimizations ?? this.disable_optimizations;
- this.completion_bias_inclusion =
- fields?.completion_bias_inclusion ?? this.completion_bias_inclusion;
- this.completion_bias_inclusion_first_token_only =
- fields?.completion_bias_inclusion_first_token_only ??
- this.completion_bias_inclusion_first_token_only;
- this.completion_bias_exclusion =
- fields?.completion_bias_exclusion ?? this.completion_bias_exclusion;
- this.completion_bias_exclusion_first_token_only =
- fields?.completion_bias_exclusion_first_token_only ??
- this.completion_bias_exclusion_first_token_only;
- this.contextual_control_threshold =
- fields?.contextual_control_threshold ?? this.contextual_control_threshold;
- this.control_log_additive =
- fields?.control_log_additive ?? this.control_log_additive;
- this.aleph_alpha_api_key =
- fields?.aleph_alpha_api_key ?? this.aleph_alpha_api_key;
- this.stop = fields?.stop ?? this.stop;
- }
-
- /**
- * Validates the environment by ensuring the necessary Aleph Alpha API key
- * is available. Throws an error if the API key is missing.
- */
- validateEnvironment() {
- if (!this.aleph_alpha_api_key) {
- throw new Error(
- "Aleph Alpha API Key is missing in environment variables."
- );
- }
- }
-
- /** Get the default parameters for calling Aleph Alpha API. */
- get defaultParams() {
- return {
- model: this.model,
- temperature: this.temperature,
- maximum_tokens: this.maximum_tokens,
- minimum_tokens: this.minimum_tokens,
- top_k: this.top_k,
- top_p: this.top_p,
- presence_penalty: this.presence_penalty,
- frequency_penalty: this.frequency_penalty,
- sequence_penalty: this.sequence_penalty,
- sequence_penalty_min_length: this.sequence_penalty_min_length,
- repetition_penalties_include_prompt:
- this.repetition_penalties_include_prompt,
- repetition_penalties_include_completion:
- this.repetition_penalties_include_completion,
- use_multiplicative_presence_penalty:
- this.use_multiplicative_presence_penalty,
- use_multiplicative_frequency_penalty:
- this.use_multiplicative_frequency_penalty,
- use_multiplicative_sequence_penalty:
- this.use_multiplicative_sequence_penalty,
- penalty_bias: this.penalty_bias,
- penalty_exceptions: this.penalty_exceptions,
- penalty_exceptions_include_stop_sequences:
- this.penalty_exceptions_include_stop_sequences,
- best_of: this.best_of,
- n: this.n,
- logit_bias: this.logit_bias,
- log_probs: this.log_probs,
- tokens: this.tokens,
- raw_completion: this.raw_completion,
- disable_optimizations: this.disable_optimizations,
- completion_bias_inclusion: this.completion_bias_inclusion,
- completion_bias_inclusion_first_token_only:
- this.completion_bias_inclusion_first_token_only,
- completion_bias_exclusion: this.completion_bias_exclusion,
- completion_bias_exclusion_first_token_only:
- this.completion_bias_exclusion_first_token_only,
- contextual_control_threshold: this.contextual_control_threshold,
- control_log_additive: this.control_log_additive,
- };
- }
-
- /** Get the identifying parameters for this LLM. */
- get identifyingParams() {
- return { ...this.defaultParams };
- }
-
- /** Get the type of LLM. */
- _llmType(): string {
- return "aleph_alpha";
- }
-
- async _call(
- prompt: string,
- options: this["ParsedCallOptions"]
- ): Promise {
- let stop = options?.stop;
- this.validateEnvironment();
- if (this.stop && stop && this.stop.length > 0 && stop.length > 0) {
- throw new Error("`stop` found in both the input and default params.");
- }
- stop = this.stop ?? stop ?? [];
- const headers = {
- Authorization: `Bearer ${this.aleph_alpha_api_key}`,
- "Content-Type": "application/json",
- Accept: "application/json",
- };
- const data = { prompt, stop_sequences: stop, ...this.defaultParams };
- const responseData = await this.caller.call(async () => {
- const response = await fetch(this.base_url, {
- method: "POST",
- headers,
- body: JSON.stringify(data),
- signal: options.signal,
- });
- if (!response.ok) {
- // consume the response body to release the connection
- // https://undici.nodejs.org/#/?id=garbage-collection
- const text = await response.text();
- const error = new Error(
- `Aleph Alpha call failed with status ${response.status} and body ${text}`
- );
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- (error as any).response = response;
- throw error;
- }
- return response.json();
- });
-
- if (
- !responseData.completions ||
- responseData.completions.length === 0 ||
- !responseData.completions[0].completion
- ) {
- throw new Error("No completions found in response");
- }
-
- return responseData.completions[0].completion ?? "";
- }
-}
+export * from "@langchain/community/llms/aleph_alpha";
diff --git a/langchain/src/llms/bedrock/web.ts b/langchain/src/llms/bedrock/web.ts
index f10660c9feab..3ed2ccdd2650 100644
--- a/langchain/src/llms/bedrock/web.ts
+++ b/langchain/src/llms/bedrock/web.ts
@@ -1,356 +1 @@
-import { SignatureV4 } from "@smithy/signature-v4";
-
-import { HttpRequest } from "@smithy/protocol-http";
-import { EventStreamCodec } from "@smithy/eventstream-codec";
-import { fromUtf8, toUtf8 } from "@smithy/util-utf8";
-import { Sha256 } from "@aws-crypto/sha256-js";
-
-import {
- BaseBedrockInput,
- BedrockLLMInputOutputAdapter,
- type CredentialType,
-} from "../../util/bedrock.js";
-import { getEnvironmentVariable } from "../../util/env.js";
-import { LLM, BaseLLMParams } from "../base.js";
-import { CallbackManagerForLLMRun } from "../../callbacks/manager.js";
-import { GenerationChunk } from "../../schema/index.js";
-import type { SerializedFields } from "../../load/map_keys.js";
-
-/**
- * A type of Large Language Model (LLM) that interacts with the Bedrock
- * service. It extends the base `LLM` class and implements the
- * `BaseBedrockInput` interface. The class is designed to authenticate and
- * interact with the Bedrock service, which is a part of Amazon Web
- * Services (AWS). It uses AWS credentials for authentication and can be
- * configured with various parameters such as the model to use, the AWS
- * region, and the maximum number of tokens to generate.
- */
-export class Bedrock extends LLM implements BaseBedrockInput {
- model = "amazon.titan-tg1-large";
-
- region: string;
-
- credentials: CredentialType;
-
- temperature?: number | undefined = undefined;
-
- maxTokens?: number | undefined = undefined;
-
- fetchFn: typeof fetch;
-
- endpointHost?: string;
-
- /** @deprecated */
- stopSequences?: string[];
-
- modelKwargs?: Record;
-
- codec: EventStreamCodec = new EventStreamCodec(toUtf8, fromUtf8);
-
- streaming = false;
-
- lc_serializable = true;
-
- get lc_aliases(): Record {
- return {
- model: "model_id",
- region: "region_name",
- };
- }
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- "credentials.accessKeyId": "BEDROCK_AWS_ACCESS_KEY_ID",
- "credentials.secretAccessKey": "BEDROCK_AWS_SECRET_ACCESS_KEY",
- };
- }
-
- get lc_attributes(): SerializedFields | undefined {
- return { region: this.region };
- }
-
- _llmType() {
- return "bedrock";
- }
-
- static lc_name() {
- return "Bedrock";
- }
-
- constructor(fields?: Partial & BaseLLMParams) {
- super(fields ?? {});
-
- this.model = fields?.model ?? this.model;
- const allowedModels = ["ai21", "anthropic", "amazon", "cohere", "meta"];
- if (!allowedModels.includes(this.model.split(".")[0])) {
- throw new Error(
- `Unknown model: '${this.model}', only these are supported: ${allowedModels}`
- );
- }
- const region =
- fields?.region ?? getEnvironmentVariable("AWS_DEFAULT_REGION");
- if (!region) {
- throw new Error(
- "Please set the AWS_DEFAULT_REGION environment variable or pass it to the constructor as the region field."
- );
- }
- this.region = region;
-
- const credentials = fields?.credentials;
- if (!credentials) {
- throw new Error(
- "Please set the AWS credentials in the 'credentials' field."
- );
- }
- this.credentials = credentials;
-
- this.temperature = fields?.temperature ?? this.temperature;
- this.maxTokens = fields?.maxTokens ?? this.maxTokens;
- this.fetchFn = fields?.fetchFn ?? fetch.bind(globalThis);
- this.endpointHost = fields?.endpointHost ?? fields?.endpointUrl;
- this.stopSequences = fields?.stopSequences;
- this.modelKwargs = fields?.modelKwargs;
- this.streaming = fields?.streaming ?? this.streaming;
- }
-
- /** Call out to Bedrock service model.
- Arguments:
- prompt: The prompt to pass into the model.
-
- Returns:
- The string generated by the model.
-
- Example:
- response = model.call("Tell me a joke.")
- */
- async _call(
- prompt: string,
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): Promise {
- const service = "bedrock-runtime";
- const endpointHost =
- this.endpointHost ?? `${service}.${this.region}.amazonaws.com`;
- const provider = this.model.split(".")[0];
- if (this.streaming) {
- const stream = this._streamResponseChunks(prompt, options, runManager);
- let finalResult: GenerationChunk | undefined;
- for await (const chunk of stream) {
- if (finalResult === undefined) {
- finalResult = chunk;
- } else {
- finalResult = finalResult.concat(chunk);
- }
- }
- return finalResult?.text ?? "";
- }
- const response = await this._signedFetch(prompt, options, {
- bedrockMethod: "invoke",
- endpointHost,
- provider,
- });
- const json = await response.json();
- if (!response.ok) {
- throw new Error(
- `Error ${response.status}: ${json.message ?? JSON.stringify(json)}`
- );
- }
- const text = BedrockLLMInputOutputAdapter.prepareOutput(provider, json);
- return text;
- }
-
- async _signedFetch(
- prompt: string,
- options: this["ParsedCallOptions"],
- fields: {
- bedrockMethod: "invoke" | "invoke-with-response-stream";
- endpointHost: string;
- provider: string;
- }
- ) {
- const { bedrockMethod, endpointHost, provider } = fields;
- const inputBody = BedrockLLMInputOutputAdapter.prepareInput(
- provider,
- prompt,
- this.maxTokens,
- this.temperature,
- options.stop ?? this.stopSequences,
- this.modelKwargs,
- fields.bedrockMethod
- );
-
- const url = new URL(
- `https://${endpointHost}/model/${this.model}/${bedrockMethod}`
- );
-
- const request = new HttpRequest({
- hostname: url.hostname,
- path: url.pathname,
- protocol: url.protocol,
- method: "POST", // method must be uppercase
- body: JSON.stringify(inputBody),
- query: Object.fromEntries(url.searchParams.entries()),
- headers: {
- // host is required by AWS Signature V4: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
- host: url.host,
- accept: "application/json",
- "content-type": "application/json",
- },
- });
-
- const signer = new SignatureV4({
- credentials: this.credentials,
- service: "bedrock",
- region: this.region,
- sha256: Sha256,
- });
-
- const signedRequest = await signer.sign(request);
-
- // Send request to AWS using the low-level fetch API
- const response = await this.caller.callWithOptions(
- { signal: options.signal },
- async () =>
- this.fetchFn(url, {
- headers: signedRequest.headers,
- body: signedRequest.body,
- method: signedRequest.method,
- })
- );
- return response;
- }
-
- invocationParams(options?: this["ParsedCallOptions"]) {
- return {
- model: this.model,
- region: this.region,
- temperature: this.temperature,
- maxTokens: this.maxTokens,
- stop: options?.stop ?? this.stopSequences,
- modelKwargs: this.modelKwargs,
- };
- }
-
- async *_streamResponseChunks(
- prompt: string,
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): AsyncGenerator {
- const provider = this.model.split(".")[0];
- const bedrockMethod =
- provider === "anthropic" || provider === "cohere" || provider === "meta"
- ? "invoke-with-response-stream"
- : "invoke";
-
- const service = "bedrock-runtime";
- const endpointHost =
- this.endpointHost ?? `${service}.${this.region}.amazonaws.com`;
-
- // Send request to AWS using the low-level fetch API
- const response = await this._signedFetch(prompt, options, {
- bedrockMethod,
- endpointHost,
- provider,
- });
-
- if (response.status < 200 || response.status >= 300) {
- throw Error(
- `Failed to access underlying url '${endpointHost}': got ${
- response.status
- } ${response.statusText}: ${await response.text()}`
- );
- }
-
- if (
- provider === "anthropic" ||
- provider === "cohere" ||
- provider === "meta"
- ) {
- const reader = response.body?.getReader();
- const decoder = new TextDecoder();
- for await (const chunk of this._readChunks(reader)) {
- const event = this.codec.decode(chunk);
- if (
- (event.headers[":event-type"] !== undefined &&
- event.headers[":event-type"].value !== "chunk") ||
- event.headers[":content-type"].value !== "application/json"
- ) {
- throw Error(`Failed to get event chunk: got ${chunk}`);
- }
- const body = JSON.parse(decoder.decode(event.body));
- if (body.message) {
- throw new Error(body.message);
- }
- if (body.bytes !== undefined) {
- const chunkResult = JSON.parse(
- decoder.decode(
- Uint8Array.from(atob(body.bytes), (m) => m.codePointAt(0) ?? 0)
- )
- );
- const text = BedrockLLMInputOutputAdapter.prepareOutput(
- provider,
- chunkResult
- );
- yield new GenerationChunk({
- text,
- generationInfo: {},
- });
- // eslint-disable-next-line no-void
- void runManager?.handleLLMNewToken(text);
- }
- }
- } else {
- const json = await response.json();
- const text = BedrockLLMInputOutputAdapter.prepareOutput(provider, json);
- yield new GenerationChunk({
- text,
- generationInfo: {},
- });
- // eslint-disable-next-line no-void
- void runManager?.handleLLMNewToken(text);
- }
- }
-
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- _readChunks(reader: any) {
- function _concatChunks(a: Uint8Array, b: Uint8Array) {
- const newBuffer = new Uint8Array(a.length + b.length);
- newBuffer.set(a);
- newBuffer.set(b, a.length);
- return newBuffer;
- }
-
- function getMessageLength(buffer: Uint8Array) {
- if (buffer.byteLength === 0) return 0;
- const view = new DataView(
- buffer.buffer,
- buffer.byteOffset,
- buffer.byteLength
- );
-
- return view.getUint32(0, false);
- }
-
- return {
- async *[Symbol.asyncIterator]() {
- let readResult = await reader.read();
-
- let buffer: Uint8Array = new Uint8Array(0);
- while (!readResult.done) {
- const chunk: Uint8Array = readResult.value;
-
- buffer = _concatChunks(buffer, chunk);
- let messageLength = getMessageLength(buffer);
-
- while (buffer.byteLength > 0 && buffer.byteLength >= messageLength) {
- yield buffer.slice(0, messageLength);
- buffer = buffer.slice(messageLength);
- messageLength = getMessageLength(buffer);
- }
-
- readResult = await reader.read();
- }
- },
- };
- }
-}
+export * from "@langchain/community/llms/bedrock/web";
diff --git a/langchain/src/llms/cloudflare_workersai.ts b/langchain/src/llms/cloudflare_workersai.ts
index 25c6b5a16276..2e5add32a465 100644
--- a/langchain/src/llms/cloudflare_workersai.ts
+++ b/langchain/src/llms/cloudflare_workersai.ts
@@ -1,189 +1 @@
-import { LLM, BaseLLMParams } from "./base.js";
-import { getEnvironmentVariable } from "../util/env.js";
-import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import { GenerationChunk } from "../schema/index.js";
-import { convertEventStreamToIterableReadableDataStream } from "../util/event-source-parse.js";
-
-/**
- * Interface for CloudflareWorkersAI input parameters.
- */
-export interface CloudflareWorkersAIInput {
- cloudflareAccountId?: string;
- cloudflareApiToken?: string;
- model?: string;
- baseUrl?: string;
- streaming?: boolean;
-}
-
-/**
- * Class representing the CloudflareWorkersAI language model. It extends the LLM (Large
- * Language Model) class, providing a standard interface for interacting
- * with the CloudflareWorkersAI language model.
- */
-export class CloudflareWorkersAI
- extends LLM
- implements CloudflareWorkersAIInput
-{
- model = "@cf/meta/llama-2-7b-chat-int8";
-
- cloudflareAccountId?: string;
-
- cloudflareApiToken?: string;
-
- baseUrl: string;
-
- streaming = false;
-
- static lc_name() {
- return "CloudflareWorkersAI";
- }
-
- lc_serializable = true;
-
- constructor(fields?: CloudflareWorkersAIInput & BaseLLMParams) {
- super(fields ?? {});
-
- this.model = fields?.model ?? this.model;
- this.streaming = fields?.streaming ?? this.streaming;
- this.cloudflareAccountId =
- fields?.cloudflareAccountId ??
- getEnvironmentVariable("CLOUDFLARE_ACCOUNT_ID");
- this.cloudflareApiToken =
- fields?.cloudflareApiToken ??
- getEnvironmentVariable("CLOUDFLARE_API_TOKEN");
- this.baseUrl =
- fields?.baseUrl ??
- `https://api.cloudflare.com/client/v4/accounts/${this.cloudflareAccountId}/ai/run`;
- if (this.baseUrl.endsWith("/")) {
- this.baseUrl = this.baseUrl.slice(0, -1);
- }
- }
-
- /**
- * Method to validate the environment.
- */
- validateEnvironment() {
- if (this.baseUrl === undefined) {
- if (!this.cloudflareAccountId) {
- throw new Error(
- `No Cloudflare account ID found. Please provide it when instantiating the CloudflareWorkersAI class, or set it as "CLOUDFLARE_ACCOUNT_ID" in your environment variables.`
- );
- }
- if (!this.cloudflareApiToken) {
- throw new Error(
- `No Cloudflare API key found. Please provide it when instantiating the CloudflareWorkersAI class, or set it as "CLOUDFLARE_API_KEY" in your environment variables.`
- );
- }
- }
- }
-
- /** Get the identifying parameters for this LLM. */
- get identifyingParams() {
- return { model: this.model };
- }
-
- /**
- * Get the parameters used to invoke the model
- */
- invocationParams() {
- return {
- model: this.model,
- };
- }
-
- /** Get the type of LLM. */
- _llmType() {
- return "cloudflare";
- }
-
- async _request(
- prompt: string,
- options: this["ParsedCallOptions"],
- stream?: boolean
- ) {
- this.validateEnvironment();
-
- const url = `${this.baseUrl}/${this.model}`;
- const headers = {
- Authorization: `Bearer ${this.cloudflareApiToken}`,
- "Content-Type": "application/json",
- };
-
- const data = { prompt, stream };
- return this.caller.call(async () => {
- const response = await fetch(url, {
- method: "POST",
- headers,
- body: JSON.stringify(data),
- signal: options.signal,
- });
- if (!response.ok) {
- const error = new Error(
- `Cloudflare LLM call failed with status code ${response.status}`
- );
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- (error as any).response = response;
- throw error;
- }
- return response;
- });
- }
-
- async *_streamResponseChunks(
- prompt: string,
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): AsyncGenerator {
- const response = await this._request(prompt, options, true);
- if (!response.body) {
- throw new Error("Empty response from Cloudflare. Please try again.");
- }
- const stream = convertEventStreamToIterableReadableDataStream(
- response.body
- );
- for await (const chunk of stream) {
- if (chunk !== "[DONE]") {
- const parsedChunk = JSON.parse(chunk);
- const generationChunk = new GenerationChunk({
- text: parsedChunk.response,
- });
- yield generationChunk;
- // eslint-disable-next-line no-void
- void runManager?.handleLLMNewToken(generationChunk.text ?? "");
- }
- }
- }
-
- /** Call out to CloudflareWorkersAI's complete endpoint.
- Args:
- prompt: The prompt to pass into the model.
- Returns:
- The string generated by the model.
- Example:
- let response = CloudflareWorkersAI.call("Tell me a joke.");
- */
- async _call(
- prompt: string,
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): Promise {
- if (!this.streaming) {
- const response = await this._request(prompt, options);
-
- const responseData = await response.json();
-
- return responseData.result.response;
- } else {
- const stream = this._streamResponseChunks(prompt, options, runManager);
- let finalResult: GenerationChunk | undefined;
- for await (const chunk of stream) {
- if (finalResult === undefined) {
- finalResult = chunk;
- } else {
- finalResult = finalResult.concat(chunk);
- }
- }
- return finalResult?.text ?? "";
- }
- }
-}
+export * from "@langchain/community/llms/cloudflare_workersai";
diff --git a/langchain/src/llms/cohere.ts b/langchain/src/llms/cohere.ts
index 393876efb939..8b911819109e 100644
--- a/langchain/src/llms/cohere.ts
+++ b/langchain/src/llms/cohere.ts
@@ -1,129 +1 @@
-import { getEnvironmentVariable } from "../util/env.js";
-import { LLM, BaseLLMParams } from "./base.js";
-
-/**
- * Interface for the input parameters specific to the Cohere model.
- */
-export interface CohereInput extends BaseLLMParams {
- /** Sampling temperature to use */
- temperature?: number;
-
- /**
- * Maximum number of tokens to generate in the completion.
- */
- maxTokens?: number;
-
- /** Model to use */
- model?: string;
-
- apiKey?: string;
-}
-
-/**
- * Class representing a Cohere Large Language Model (LLM). It interacts
- * with the Cohere API to generate text completions.
- * @example
- * ```typescript
- * const model = new Cohere({
- * temperature: 0.7,
- * maxTokens: 20,
- * maxRetries: 5,
- * });
- *
- * const res = await model.call(
- * "Question: What would be a good company name for a company that makes colorful socks?\nAnswer:"
- * );
- * console.log({ res });
- * ```
- */
-export class Cohere extends LLM implements CohereInput {
- static lc_name() {
- return "Cohere";
- }
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- apiKey: "COHERE_API_KEY",
- };
- }
-
- get lc_aliases(): { [key: string]: string } | undefined {
- return {
- apiKey: "cohere_api_key",
- };
- }
-
- lc_serializable = true;
-
- temperature = 0;
-
- maxTokens = 250;
-
- model: string;
-
- apiKey: string;
-
- constructor(fields?: CohereInput) {
- super(fields ?? {});
-
- const apiKey = fields?.apiKey ?? getEnvironmentVariable("COHERE_API_KEY");
-
- if (!apiKey) {
- throw new Error(
- "Please set the COHERE_API_KEY environment variable or pass it to the constructor as the apiKey field."
- );
- }
-
- this.apiKey = apiKey;
- this.maxTokens = fields?.maxTokens ?? this.maxTokens;
- this.temperature = fields?.temperature ?? this.temperature;
- this.model = fields?.model ?? this.model;
- }
-
- _llmType() {
- return "cohere";
- }
-
- /** @ignore */
- async _call(
- prompt: string,
- options: this["ParsedCallOptions"]
- ): Promise {
- const { cohere } = await Cohere.imports();
-
- cohere.init(this.apiKey);
-
- // Hit the `generate` endpoint on the `large` model
- const generateResponse = await this.caller.callWithOptions(
- { signal: options.signal },
- cohere.generate.bind(cohere),
- {
- prompt,
- model: this.model,
- max_tokens: this.maxTokens,
- temperature: this.temperature,
- end_sequences: options.stop,
- }
- );
- try {
- return generateResponse.body.generations[0].text;
- } catch {
- console.log(generateResponse);
- throw new Error("Could not parse response.");
- }
- }
-
- /** @ignore */
- static async imports(): Promise<{
- cohere: typeof import("cohere-ai");
- }> {
- try {
- const { default: cohere } = await import("cohere-ai");
- return { cohere };
- } catch (e) {
- throw new Error(
- "Please install cohere-ai as a dependency with, e.g. `yarn add cohere-ai`"
- );
- }
- }
-}
+export * from "@langchain/community/llms/cohere";
diff --git a/langchain/src/llms/fireworks.ts b/langchain/src/llms/fireworks.ts
index 8dd5981aad69..c8ff87b2d830 100644
--- a/langchain/src/llms/fireworks.ts
+++ b/langchain/src/llms/fireworks.ts
@@ -1,140 +1 @@
-import type { OpenAI as OpenAIClient } from "openai";
-
-import type { BaseLLMParams } from "./base.js";
-import type { OpenAICallOptions, OpenAIInput } from "./openai.js";
-import type { OpenAICoreRequestOptions } from "../types/openai-types.js";
-import { getEnvironmentVariable } from "../util/env.js";
-import { OpenAI } from "./openai.js";
-
-type FireworksUnsupportedArgs =
- | "frequencyPenalty"
- | "presencePenalty"
- | "bestOf"
- | "logitBias";
-
-type FireworksUnsupportedCallOptions = "functions" | "function_call" | "tools";
-
-export type FireworksCallOptions = Partial<
- Omit
->;
-
-/**
- * Wrapper around Fireworks API for large language models
- *
- * Fireworks API is compatible to the OpenAI API with some limitations described in
- * https://readme.fireworks.ai/docs/openai-compatibility.
- *
- * To use, you should have the `openai` package installed and
- * the `FIREWORKS_API_KEY` environment variable set.
- */
-export class Fireworks extends OpenAI {
- static lc_name() {
- return "Fireworks";
- }
-
- _llmType() {
- return "fireworks";
- }
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- fireworksApiKey: "FIREWORKS_API_KEY",
- };
- }
-
- lc_serializable = true;
-
- fireworksApiKey?: string;
-
- constructor(
- fields?: Partial<
- Omit
- > &
- BaseLLMParams & { fireworksApiKey?: string }
- ) {
- const fireworksApiKey =
- fields?.fireworksApiKey || getEnvironmentVariable("FIREWORKS_API_KEY");
-
- if (!fireworksApiKey) {
- throw new Error(
- `Fireworks API key not found. Please set the FIREWORKS_API_KEY environment variable or provide the key into "fireworksApiKey"`
- );
- }
-
- super({
- ...fields,
- openAIApiKey: fireworksApiKey,
- modelName: fields?.modelName || "accounts/fireworks/models/llama-v2-13b",
- configuration: {
- baseURL: "https://api.fireworks.ai/inference/v1",
- },
- });
-
- this.fireworksApiKey = fireworksApiKey;
- }
-
- toJSON() {
- const result = super.toJSON();
-
- if (
- "kwargs" in result &&
- typeof result.kwargs === "object" &&
- result.kwargs != null
- ) {
- delete result.kwargs.openai_api_key;
- delete result.kwargs.configuration;
- }
-
- return result;
- }
-
- async completionWithRetry(
- request: OpenAIClient.CompletionCreateParamsStreaming,
- options?: OpenAICoreRequestOptions
- ): Promise>;
-
- async completionWithRetry(
- request: OpenAIClient.CompletionCreateParamsNonStreaming,
- options?: OpenAICoreRequestOptions
- ): Promise;
-
- /**
- * Calls the Fireworks API with retry logic in case of failures.
- * @param request The request to send to the Fireworks API.
- * @param options Optional configuration for the API call.
- * @returns The response from the Fireworks API.
- */
- async completionWithRetry(
- request:
- | OpenAIClient.CompletionCreateParamsStreaming
- | OpenAIClient.CompletionCreateParamsNonStreaming,
- options?: OpenAICoreRequestOptions
- ): Promise<
- AsyncIterable | OpenAIClient.Completions.Completion
- > {
- // https://readme.fireworks.ai/docs/openai-compatibility#api-compatibility
- if (Array.isArray(request.prompt)) {
- if (request.prompt.length > 1) {
- throw new Error("Multiple prompts are not supported by Fireworks");
- }
-
- const prompt = request.prompt[0];
- if (typeof prompt !== "string") {
- throw new Error("Only string prompts are supported by Fireworks");
- }
-
- request.prompt = prompt;
- }
-
- delete request.frequency_penalty;
- delete request.presence_penalty;
- delete request.best_of;
- delete request.logit_bias;
-
- if (request.stream === true) {
- return super.completionWithRetry(request, options);
- }
-
- return super.completionWithRetry(request, options);
- }
-}
+export * from "@langchain/community/llms/fireworks";
diff --git a/langchain/src/llms/googlepalm.ts b/langchain/src/llms/googlepalm.ts
index 2bd8d8d2fc49..5e95faa32f13 100644
--- a/langchain/src/llms/googlepalm.ts
+++ b/langchain/src/llms/googlepalm.ts
@@ -1,203 +1 @@
-import { TextServiceClient, protos } from "@google-ai/generativelanguage";
-import { GoogleAuth } from "google-auth-library";
-import { BaseLLMParams, LLM } from "./base.js";
-import { getEnvironmentVariable } from "../util/env.js";
-
-/**
- * Input for Text generation for Google Palm
- */
-export interface GooglePaLMTextInput extends BaseLLMParams {
- /**
- * Model Name to use
- *
- * Note: The format must follow the pattern - `models/{model}`
- */
- modelName?: string;
-
- /**
- * Controls the randomness of the output.
- *
- * Values can range from [0.0,1.0], inclusive. A value closer to 1.0
- * will produce responses that are more varied and creative, while
- * a value closer to 0.0 will typically result in more straightforward
- * responses from the model.
- *
- * Note: The default value varies by model
- */
- temperature?: number;
-
- /**
- * Maximum number of tokens to generate in the completion.
- */
- maxOutputTokens?: number;
-
- /**
- * Top-p changes how the model selects tokens for output.
- *
- * Tokens are selected from most probable to least until the sum
- * of their probabilities equals the top-p value.
- *
- * For example, if tokens A, B, and C have a probability of
- * .3, .2, and .1 and the top-p value is .5, then the model will
- * select either A or B as the next token (using temperature).
- *
- * Note: The default value varies by model
- */
- topP?: number;
-
- /**
- * Top-k changes how the model selects tokens for output.
- *
- * A top-k of 1 means the selected token is the most probable among
- * all tokens in the model’s vocabulary (also called greedy decoding),
- * while a top-k of 3 means that the next token is selected from
- * among the 3 most probable tokens (using temperature).
- *
- * Note: The default value varies by model
- */
- topK?: number;
-
- /**
- * The set of character sequences (up to 5) that will stop output generation.
- * If specified, the API will stop at the first appearance of a stop
- * sequence.
- *
- * Note: The stop sequence will not be included as part of the response.
- */
- stopSequences?: string[];
-
- /**
- * A list of unique `SafetySetting` instances for blocking unsafe content. The API will block
- * any prompts and responses that fail to meet the thresholds set by these settings. If there
- * is no `SafetySetting` for a given `SafetyCategory` provided in the list, the API will use
- * the default safety setting for that category.
- */
- safetySettings?: protos.google.ai.generativelanguage.v1beta2.ISafetySetting[];
-
- /**
- * Google Palm API key to use
- */
- apiKey?: string;
-}
-
-/**
- * Google Palm 2 Language Model Wrapper to generate texts
- */
-export class GooglePaLM extends LLM implements GooglePaLMTextInput {
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- apiKey: "GOOGLE_PALM_API_KEY",
- };
- }
-
- modelName = "models/text-bison-001";
-
- temperature?: number; // default value chosen based on model
-
- maxOutputTokens?: number; // defaults to 64
-
- topP?: number; // default value chosen based on model
-
- topK?: number; // default value chosen based on model
-
- stopSequences: string[] = [];
-
- safetySettings?: protos.google.ai.generativelanguage.v1beta2.ISafetySetting[]; // default safety setting for that category
-
- apiKey?: string;
-
- private client: TextServiceClient;
-
- constructor(fields?: GooglePaLMTextInput) {
- super(fields ?? {});
-
- this.modelName = fields?.modelName ?? this.modelName;
-
- this.temperature = fields?.temperature ?? this.temperature;
- if (this.temperature && (this.temperature < 0 || this.temperature > 1)) {
- throw new Error("`temperature` must be in the range of [0.0,1.0]");
- }
-
- this.maxOutputTokens = fields?.maxOutputTokens ?? this.maxOutputTokens;
- if (this.maxOutputTokens && this.maxOutputTokens < 0) {
- throw new Error("`maxOutputTokens` must be a positive integer");
- }
-
- this.topP = fields?.topP ?? this.topP;
- if (this.topP && this.topP < 0) {
- throw new Error("`topP` must be a positive integer");
- }
-
- if (this.topP && this.topP > 1) {
- throw new Error("Google PaLM `topP` must in the range of [0,1]");
- }
-
- this.topK = fields?.topK ?? this.topK;
- if (this.topK && this.topK < 0) {
- throw new Error("`topK` must be a positive integer");
- }
-
- this.stopSequences = fields?.stopSequences ?? this.stopSequences;
-
- this.safetySettings = fields?.safetySettings ?? this.safetySettings;
- if (this.safetySettings && this.safetySettings.length > 0) {
- const safetySettingsSet = new Set(
- this.safetySettings.map((s) => s.category)
- );
- if (safetySettingsSet.size !== this.safetySettings.length) {
- throw new Error(
- "The categories in `safetySettings` array must be unique"
- );
- }
- }
-
- this.apiKey =
- fields?.apiKey ?? getEnvironmentVariable("GOOGLE_PALM_API_KEY");
- if (!this.apiKey) {
- throw new Error(
- "Please set an API key for Google Palm 2 in the environment variable GOOGLE_PALM_API_KEY or in the `apiKey` field of the GooglePalm constructor"
- );
- }
-
- this.client = new TextServiceClient({
- authClient: new GoogleAuth().fromAPIKey(this.apiKey),
- });
- }
-
- _llmType(): string {
- return "googlepalm";
- }
-
- async _call(
- prompt: string,
- options: this["ParsedCallOptions"]
- ): Promise {
- const res = await this.caller.callWithOptions(
- { signal: options.signal },
- this._generateText.bind(this),
- prompt
- );
- return res ?? "";
- }
-
- protected async _generateText(
- prompt: string
- ): Promise {
- const res = await this.client.generateText({
- model: this.modelName,
- temperature: this.temperature,
- candidateCount: 1,
- topK: this.topK,
- topP: this.topP,
- maxOutputTokens: this.maxOutputTokens,
- stopSequences: this.stopSequences,
- safetySettings: this.safetySettings,
- prompt: {
- text: prompt,
- },
- });
- return res[0].candidates && res[0].candidates.length > 0
- ? res[0].candidates[0].output
- : undefined;
- }
-}
+export * from "@langchain/community/llms/googlepalm";
diff --git a/langchain/src/llms/googlevertexai/index.ts b/langchain/src/llms/googlevertexai/index.ts
index c3c7cbd6127a..0616e82bdd49 100644
--- a/langchain/src/llms/googlevertexai/index.ts
+++ b/langchain/src/llms/googlevertexai/index.ts
@@ -1,66 +1 @@
-import { GoogleAuthOptions } from "google-auth-library";
-import { GoogleVertexAILLMConnection } from "../../util/googlevertexai-connection.js";
-import { GoogleVertexAIBaseLLMInput } from "../../types/googlevertexai-types.js";
-import { BaseGoogleVertexAI } from "./common.js";
-import { GAuthClient } from "../../util/googlevertexai-gauth.js";
-
-/**
- * Interface representing the input to the Google Vertex AI model.
- */
-export interface GoogleVertexAITextInput
- extends GoogleVertexAIBaseLLMInput {}
-
-/**
- * Enables calls to the Google Cloud's Vertex AI API to access
- * Large Language Models.
- *
- * To use, you will need to have one of the following authentication
- * methods in place:
- * - You are logged into an account permitted to the Google Cloud project
- * using Vertex AI.
- * - You are running this on a machine using a service account permitted to
- * the Google Cloud project using Vertex AI.
- * - The `GOOGLE_APPLICATION_CREDENTIALS` environment variable is set to the
- * path of a credentials file for a service account permitted to the
- * Google Cloud project using Vertex AI.
- * @example
- * ```typescript
- * const model = new GoogleVertexAI({
- * temperature: 0.7,
- * });
- * const stream = await model.stream(
- * "What would be a good company name for a company that makes colorful socks?",
- * );
- * for await (const chunk of stream) {
- * console.log(chunk);
- * }
- * ```
- */
-export class GoogleVertexAI extends BaseGoogleVertexAI {
- static lc_name() {
- return "VertexAI";
- }
-
- constructor(fields?: GoogleVertexAITextInput) {
- super(fields);
-
- const client = new GAuthClient({
- scopes: "https://www.googleapis.com/auth/cloud-platform",
- ...fields?.authOptions,
- });
-
- this.connection = new GoogleVertexAILLMConnection(
- { ...fields, ...this },
- this.caller,
- client,
- false
- );
-
- this.streamedConnection = new GoogleVertexAILLMConnection(
- { ...fields, ...this },
- this.caller,
- client,
- true
- );
- }
-}
+export * from "@langchain/community/llms/googlevertexai";
diff --git a/langchain/src/llms/googlevertexai/web.ts b/langchain/src/llms/googlevertexai/web.ts
index 0b656308d53b..cecd871df86d 100644
--- a/langchain/src/llms/googlevertexai/web.ts
+++ b/langchain/src/llms/googlevertexai/web.ts
@@ -1,66 +1 @@
-import {
- WebGoogleAuth,
- WebGoogleAuthOptions,
-} from "../../util/googlevertexai-webauth.js";
-import { GoogleVertexAILLMConnection } from "../../util/googlevertexai-connection.js";
-import { GoogleVertexAIBaseLLMInput } from "../../types/googlevertexai-types.js";
-import { BaseGoogleVertexAI } from "./common.js";
-
-/**
- * Interface representing the input to the Google Vertex AI model.
- */
-export interface GoogleVertexAITextInput
- extends GoogleVertexAIBaseLLMInput {}
-
-/**
- * Enables calls to the Google Cloud's Vertex AI API to access
- * Large Language Models.
- *
- * This entrypoint and class are intended to be used in web environments like Edge
- * functions where you do not have access to the file system. It supports passing
- * service account credentials directly as a "GOOGLE_VERTEX_AI_WEB_CREDENTIALS"
- * environment variable or directly as "authOptions.credentials".
- * @example
- * ```typescript
- * const model = new GoogleVertexAI({
- * temperature: 0.7,
- * });
- * const stream = await model.stream(
- * "What would be a good company name for a company that makes colorful socks?",
- * );
- * for await (const chunk of stream) {
- * console.log(chunk);
- * }
- * ```
- */
-export class GoogleVertexAI extends BaseGoogleVertexAI {
- static lc_name() {
- return "VertexAI";
- }
-
- get lc_secrets(): { [key: string]: string } {
- return {
- "authOptions.credentials": "GOOGLE_VERTEX_AI_WEB_CREDENTIALS",
- };
- }
-
- constructor(fields?: GoogleVertexAITextInput) {
- super(fields);
-
- const client = new WebGoogleAuth(fields?.authOptions);
-
- this.connection = new GoogleVertexAILLMConnection(
- { ...fields, ...this },
- this.caller,
- client,
- false
- );
-
- this.streamedConnection = new GoogleVertexAILLMConnection(
- { ...fields, ...this },
- this.caller,
- client,
- true
- );
- }
-}
+export * from "@langchain/community/llms/googlevertexai/web";
diff --git a/langchain/src/llms/gradient_ai.ts b/langchain/src/llms/gradient_ai.ts
index 782bb8cd114e..f6a15989551a 100644
--- a/langchain/src/llms/gradient_ai.ts
+++ b/langchain/src/llms/gradient_ai.ts
@@ -1,136 +1 @@
-import { Gradient } from "@gradientai/nodejs-sdk";
-import { BaseLLMCallOptions, BaseLLMParams, LLM } from "./base.js";
-import { getEnvironmentVariable } from "../util/env.js";
-
-/**
- * The GradientLLMParams interface defines the input parameters for
- * the GradientLLM class.
- */
-export interface GradientLLMParams extends BaseLLMParams {
- /**
- * Gradient AI Access Token.
- * Provide Access Token if you do not wish to automatically pull from env.
- */
- gradientAccessKey?: string;
- /**
- * Gradient Workspace Id.
- * Provide workspace id if you do not wish to automatically pull from env.
- */
- workspaceId?: string;
- /**
- * Parameters accepted by the Gradient npm package.
- */
- inferenceParameters?: Record;
- /**
- * Gradient AI Model Slug.
- */
- modelSlug?: string;
- /**
- * Gradient Adapter ID for custom fine tuned models.
- */
- adapterId?: string;
-}
-
-/**
- * The GradientLLM class is used to interact with Gradient AI inference Endpoint models.
- * This requires your Gradient AI Access Token which is autoloaded if not specified.
- */
-export class GradientLLM extends LLM {
- static lc_name() {
- return "GradientLLM";
- }
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- gradientAccessKey: "GRADIENT_ACCESS_TOKEN",
- workspaceId: "GRADIENT_WORKSPACE_ID",
- };
- }
-
- modelSlug = "llama2-7b-chat";
-
- adapterId?: string;
-
- gradientAccessKey?: string;
-
- workspaceId?: string;
-
- inferenceParameters?: Record;
-
- // Gradient AI does not export the BaseModel type. Once it does, we can use it here.
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- model: any;
-
- constructor(fields: GradientLLMParams) {
- super(fields);
-
- this.modelSlug = fields?.modelSlug ?? this.modelSlug;
- this.adapterId = fields?.adapterId;
- this.gradientAccessKey =
- fields?.gradientAccessKey ??
- getEnvironmentVariable("GRADIENT_ACCESS_TOKEN");
- this.workspaceId =
- fields?.workspaceId ?? getEnvironmentVariable("GRADIENT_WORKSPACE_ID");
-
- this.inferenceParameters = fields.inferenceParameters;
-
- if (!this.gradientAccessKey) {
- throw new Error("Missing Gradient AI Access Token");
- }
-
- if (!this.workspaceId) {
- throw new Error("Missing Gradient AI Workspace ID");
- }
- }
-
- _llmType() {
- return "gradient_ai";
- }
-
- /**
- * Calls the Gradient AI endpoint and retrieves the result.
- * @param {string} prompt The input prompt.
- * @returns {Promise} A promise that resolves to the generated string.
- */
- /** @ignore */
- async _call(
- prompt: string,
- _options: this["ParsedCallOptions"]
- ): Promise {
- await this.setModel();
-
- // GradientLLM does not export the CompleteResponse type. Once it does, we can use it here.
- interface CompleteResponse {
- finishReason: string;
- generatedOutput: string;
- }
-
- const response = (await this.caller.call(async () =>
- this.model.complete({
- query: prompt,
- ...this.inferenceParameters,
- })
- )) as CompleteResponse;
-
- return response.generatedOutput;
- }
-
- async setModel() {
- if (this.model) return;
-
- const gradient = new Gradient({
- accessToken: this.gradientAccessKey,
- workspaceId: this.workspaceId,
- });
-
- if (this.adapterId) {
- this.model = await gradient.getModelAdapter({
- modelAdapterId: this.adapterId,
- });
- } else {
- this.model = await gradient.getBaseModel({
- baseModelSlug: this.modelSlug,
- });
- }
- }
-}
+export * from "@langchain/community/llms/gradient_ai";
diff --git a/langchain/src/llms/hf.ts b/langchain/src/llms/hf.ts
index e849a7acb37e..2f0e767bf6cd 100644
--- a/langchain/src/llms/hf.ts
+++ b/langchain/src/llms/hf.ts
@@ -1,155 +1 @@
-import { getEnvironmentVariable } from "../util/env.js";
-import { LLM, BaseLLMParams } from "./base.js";
-
-/**
- * Interface defining the parameters for configuring the Hugging Face
- * model for text generation.
- */
-export interface HFInput {
- /** Model to use */
- model: string;
-
- /** Custom inference endpoint URL to use */
- endpointUrl?: string;
-
- /** Sampling temperature to use */
- temperature?: number;
-
- /**
- * Maximum number of tokens to generate in the completion.
- */
- maxTokens?: number;
-
- /** Total probability mass of tokens to consider at each step */
- topP?: number;
-
- /** Integer to define the top tokens considered within the sample operation to create new text. */
- topK?: number;
-
- /** Penalizes repeated tokens according to frequency */
- frequencyPenalty?: number;
-
- /** API key to use. */
- apiKey?: string;
-
- /**
- * Credentials to use for the request. If this is a string, it will be passed straight on. If it's a boolean, true will be "include" and false will not send credentials at all.
- */
- includeCredentials?: string | boolean;
-}
-
-/**
- * Class implementing the Large Language Model (LLM) interface using the
- * Hugging Face Inference API for text generation.
- * @example
- * ```typescript
- * const model = new HuggingFaceInference({
- * model: "gpt2",
- * temperature: 0.7,
- * maxTokens: 50,
- * });
- *
- * const res = await model.call(
- * "Question: What would be a good company name for a company that makes colorful socks?\nAnswer:"
- * );
- * console.log({ res });
- * ```
- */
-export class HuggingFaceInference extends LLM implements HFInput {
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- apiKey: "HUGGINGFACEHUB_API_KEY",
- };
- }
-
- model = "gpt2";
-
- temperature: number | undefined = undefined;
-
- maxTokens: number | undefined = undefined;
-
- topP: number | undefined = undefined;
-
- topK: number | undefined = undefined;
-
- frequencyPenalty: number | undefined = undefined;
-
- apiKey: string | undefined = undefined;
-
- endpointUrl: string | undefined = undefined;
-
- includeCredentials: string | boolean | undefined = undefined;
-
- constructor(fields?: Partial & BaseLLMParams) {
- super(fields ?? {});
-
- this.model = fields?.model ?? this.model;
- this.temperature = fields?.temperature ?? this.temperature;
- this.maxTokens = fields?.maxTokens ?? this.maxTokens;
- this.topP = fields?.topP ?? this.topP;
- this.topK = fields?.topK ?? this.topK;
- this.frequencyPenalty = fields?.frequencyPenalty ?? this.frequencyPenalty;
- this.apiKey =
- fields?.apiKey ?? getEnvironmentVariable("HUGGINGFACEHUB_API_KEY");
- this.endpointUrl = fields?.endpointUrl;
- this.includeCredentials = fields?.includeCredentials;
-
- if (!this.apiKey) {
- throw new Error(
- "Please set an API key for HuggingFace Hub in the environment variable HUGGINGFACEHUB_API_KEY or in the apiKey field of the HuggingFaceInference constructor."
- );
- }
- }
-
- _llmType() {
- return "hf";
- }
-
- /** @ignore */
- async _call(
- prompt: string,
- options: this["ParsedCallOptions"]
- ): Promise {
- const { HfInference } = await HuggingFaceInference.imports();
- const hf = this.endpointUrl
- ? new HfInference(this.apiKey, {
- includeCredentials: this.includeCredentials,
- }).endpoint(this.endpointUrl)
- : new HfInference(this.apiKey, {
- includeCredentials: this.includeCredentials,
- });
-
- const res = await this.caller.callWithOptions(
- { signal: options.signal },
- hf.textGeneration.bind(hf),
- {
- model: this.model,
- parameters: {
- // make it behave similar to openai, returning only the generated text
- return_full_text: false,
- temperature: this.temperature,
- max_new_tokens: this.maxTokens,
- top_p: this.topP,
- top_k: this.topK,
- repetition_penalty: this.frequencyPenalty,
- },
- inputs: prompt,
- }
- );
- return res.generated_text;
- }
-
- /** @ignore */
- static async imports(): Promise<{
- HfInference: typeof import("@huggingface/inference").HfInference;
- }> {
- try {
- const { HfInference } = await import("@huggingface/inference");
- return { HfInference };
- } catch (e) {
- throw new Error(
- "Please install huggingface as a dependency with, e.g. `yarn add @huggingface/inference`"
- );
- }
- }
-}
+export * from "@langchain/community/llms/hf";
diff --git a/langchain/src/llms/llama_cpp.ts b/langchain/src/llms/llama_cpp.ts
index f2d6518ffd2b..ce09302c20d3 100644
--- a/langchain/src/llms/llama_cpp.ts
+++ b/langchain/src/llms/llama_cpp.ts
@@ -1,116 +1 @@
-import { LlamaModel, LlamaContext, LlamaChatSession } from "node-llama-cpp";
-import {
- LlamaBaseCppInputs,
- createLlamaModel,
- createLlamaContext,
- createLlamaSession,
-} from "../util/llama_cpp.js";
-import { LLM, BaseLLMCallOptions, BaseLLMParams } from "./base.js";
-import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import { GenerationChunk } from "../schema/index.js";
-
-/**
- * Note that the modelPath is the only required parameter. For testing you
- * can set this in the environment variable `LLAMA_PATH`.
- */
-export interface LlamaCppInputs extends LlamaBaseCppInputs, BaseLLMParams {}
-
-export interface LlamaCppCallOptions extends BaseLLMCallOptions {
- /** The maximum number of tokens the response should contain. */
- maxTokens?: number;
- /** A function called when matching the provided token array */
- onToken?: (tokens: number[]) => void;
-}
-
-/**
- * To use this model you need to have the `node-llama-cpp` module installed.
- * This can be installed using `npm install -S node-llama-cpp` and the minimum
- * version supported in version 2.0.0.
- * This also requires that have a locally built version of Llama2 installed.
- */
-export class LlamaCpp extends LLM {
- declare CallOptions: LlamaCppCallOptions;
-
- static inputs: LlamaCppInputs;
-
- maxTokens?: number;
-
- temperature?: number;
-
- topK?: number;
-
- topP?: number;
-
- trimWhitespaceSuffix?: boolean;
-
- _model: LlamaModel;
-
- _context: LlamaContext;
-
- _session: LlamaChatSession;
-
- static lc_name() {
- return "LlamaCpp";
- }
-
- constructor(inputs: LlamaCppInputs) {
- super(inputs);
- this.maxTokens = inputs?.maxTokens;
- this.temperature = inputs?.temperature;
- this.topK = inputs?.topK;
- this.topP = inputs?.topP;
- this.trimWhitespaceSuffix = inputs?.trimWhitespaceSuffix;
- this._model = createLlamaModel(inputs);
- this._context = createLlamaContext(this._model, inputs);
- this._session = createLlamaSession(this._context);
- }
-
- _llmType() {
- return "llama2_cpp";
- }
-
- /** @ignore */
- async _call(
- prompt: string,
- options?: this["ParsedCallOptions"]
- ): Promise {
- try {
- const promptOptions = {
- onToken: options?.onToken,
- maxTokens: this?.maxTokens,
- temperature: this?.temperature,
- topK: this?.topK,
- topP: this?.topP,
- trimWhitespaceSuffix: this?.trimWhitespaceSuffix,
- };
- const completion = await this._session.prompt(prompt, promptOptions);
- return completion;
- } catch (e) {
- throw new Error("Error getting prompt completion.");
- }
- }
-
- async *_streamResponseChunks(
- prompt: string,
- _options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): AsyncGenerator {
- const promptOptions = {
- temperature: this?.temperature,
- topK: this?.topK,
- topP: this?.topP,
- };
-
- const stream = await this.caller.call(async () =>
- this._context.evaluate(this._context.encode(prompt), promptOptions)
- );
-
- for await (const chunk of stream) {
- yield new GenerationChunk({
- text: this._context.decode([chunk]),
- generationInfo: {},
- });
- await runManager?.handleLLMNewToken(this._context.decode([chunk]) ?? "");
- }
- }
-}
+export * from "@langchain/community/llms/llama_cpp";
diff --git a/langchain/src/llms/ollama.ts b/langchain/src/llms/ollama.ts
index 8b5c178cfb1f..1369ed4c0c60 100644
--- a/langchain/src/llms/ollama.ts
+++ b/langchain/src/llms/ollama.ts
@@ -1,245 +1 @@
-import { LLM, BaseLLMParams } from "./base.js";
-import {
- createOllamaStream,
- OllamaInput,
- OllamaCallOptions,
-} from "../util/ollama.js";
-import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import { GenerationChunk } from "../schema/index.js";
-import type { StringWithAutocomplete } from "../util/types.js";
-
-/**
- * Class that represents the Ollama language model. It extends the base
- * LLM class and implements the OllamaInput interface.
- * @example
- * ```typescript
- * const ollama = new Ollama({
- * baseUrl: "http://api.example.com",
- * model: "llama2",
- * });
- *
- * // Streaming translation from English to German
- * const stream = await ollama.stream(
- * `Translate "I love programming" into German.`
- * );
- *
- * const chunks = [];
- * for await (const chunk of stream) {
- * chunks.push(chunk);
- * }
- *
- * console.log(chunks.join(""));
- * ```
- */
-export class Ollama extends LLM implements OllamaInput {
- static lc_name() {
- return "Ollama";
- }
-
- lc_serializable = true;
-
- model = "llama2";
-
- baseUrl = "http://localhost:11434";
-
- embeddingOnly?: boolean;
-
- f16KV?: boolean;
-
- frequencyPenalty?: number;
-
- logitsAll?: boolean;
-
- lowVram?: boolean;
-
- mainGpu?: number;
-
- mirostat?: number;
-
- mirostatEta?: number;
-
- mirostatTau?: number;
-
- numBatch?: number;
-
- numCtx?: number;
-
- numGpu?: number;
-
- numGqa?: number;
-
- numKeep?: number;
-
- numThread?: number;
-
- penalizeNewline?: boolean;
-
- presencePenalty?: number;
-
- repeatLastN?: number;
-
- repeatPenalty?: number;
-
- ropeFrequencyBase?: number;
-
- ropeFrequencyScale?: number;
-
- temperature?: number;
-
- stop?: string[];
-
- tfsZ?: number;
-
- topK?: number;
-
- topP?: number;
-
- typicalP?: number;
-
- useMLock?: boolean;
-
- useMMap?: boolean;
-
- vocabOnly?: boolean;
-
- format?: StringWithAutocomplete<"json">;
-
- constructor(fields: OllamaInput & BaseLLMParams) {
- super(fields);
- this.model = fields.model ?? this.model;
- this.baseUrl = fields.baseUrl?.endsWith("/")
- ? fields.baseUrl.slice(0, -1)
- : fields.baseUrl ?? this.baseUrl;
-
- this.embeddingOnly = fields.embeddingOnly;
- this.f16KV = fields.f16KV;
- this.frequencyPenalty = fields.frequencyPenalty;
- this.logitsAll = fields.logitsAll;
- this.lowVram = fields.lowVram;
- this.mainGpu = fields.mainGpu;
- this.mirostat = fields.mirostat;
- this.mirostatEta = fields.mirostatEta;
- this.mirostatTau = fields.mirostatTau;
- this.numBatch = fields.numBatch;
- this.numCtx = fields.numCtx;
- this.numGpu = fields.numGpu;
- this.numGqa = fields.numGqa;
- this.numKeep = fields.numKeep;
- this.numThread = fields.numThread;
- this.penalizeNewline = fields.penalizeNewline;
- this.presencePenalty = fields.presencePenalty;
- this.repeatLastN = fields.repeatLastN;
- this.repeatPenalty = fields.repeatPenalty;
- this.ropeFrequencyBase = fields.ropeFrequencyBase;
- this.ropeFrequencyScale = fields.ropeFrequencyScale;
- this.temperature = fields.temperature;
- this.stop = fields.stop;
- this.tfsZ = fields.tfsZ;
- this.topK = fields.topK;
- this.topP = fields.topP;
- this.typicalP = fields.typicalP;
- this.useMLock = fields.useMLock;
- this.useMMap = fields.useMMap;
- this.vocabOnly = fields.vocabOnly;
- this.format = fields.format;
- }
-
- _llmType() {
- return "ollama";
- }
-
- invocationParams(options?: this["ParsedCallOptions"]) {
- return {
- model: this.model,
- format: this.format,
- options: {
- embedding_only: this.embeddingOnly,
- f16_kv: this.f16KV,
- frequency_penalty: this.frequencyPenalty,
- logits_all: this.logitsAll,
- low_vram: this.lowVram,
- main_gpu: this.mainGpu,
- mirostat: this.mirostat,
- mirostat_eta: this.mirostatEta,
- mirostat_tau: this.mirostatTau,
- num_batch: this.numBatch,
- num_ctx: this.numCtx,
- num_gpu: this.numGpu,
- num_gqa: this.numGqa,
- num_keep: this.numKeep,
- num_thread: this.numThread,
- penalize_newline: this.penalizeNewline,
- presence_penalty: this.presencePenalty,
- repeat_last_n: this.repeatLastN,
- repeat_penalty: this.repeatPenalty,
- rope_frequency_base: this.ropeFrequencyBase,
- rope_frequency_scale: this.ropeFrequencyScale,
- temperature: this.temperature,
- stop: options?.stop ?? this.stop,
- tfs_z: this.tfsZ,
- top_k: this.topK,
- top_p: this.topP,
- typical_p: this.typicalP,
- use_mlock: this.useMLock,
- use_mmap: this.useMMap,
- vocab_only: this.vocabOnly,
- },
- };
- }
-
- async *_streamResponseChunks(
- prompt: string,
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): AsyncGenerator {
- const stream = await this.caller.call(async () =>
- createOllamaStream(
- this.baseUrl,
- { ...this.invocationParams(options), prompt },
- options
- )
- );
- for await (const chunk of stream) {
- if (!chunk.done) {
- yield new GenerationChunk({
- text: chunk.response,
- generationInfo: {
- ...chunk,
- response: undefined,
- },
- });
- await runManager?.handleLLMNewToken(chunk.response ?? "");
- } else {
- yield new GenerationChunk({
- text: "",
- generationInfo: {
- model: chunk.model,
- total_duration: chunk.total_duration,
- load_duration: chunk.load_duration,
- prompt_eval_count: chunk.prompt_eval_count,
- prompt_eval_duration: chunk.prompt_eval_duration,
- eval_count: chunk.eval_count,
- eval_duration: chunk.eval_duration,
- },
- });
- }
- }
- }
-
- /** @ignore */
- async _call(
- prompt: string,
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): Promise {
- const chunks = [];
- for await (const chunk of this._streamResponseChunks(
- prompt,
- options,
- runManager
- )) {
- chunks.push(chunk.text);
- }
- return chunks.join("");
- }
-}
+export * from "@langchain/community/llms/ollama";
diff --git a/langchain/src/llms/openai-chat.ts b/langchain/src/llms/openai-chat.ts
index 4077a5efde89..06cb7faf0f1d 100644
--- a/langchain/src/llms/openai-chat.ts
+++ b/langchain/src/llms/openai-chat.ts
@@ -1,471 +1,18 @@
-import { type ClientOptions, OpenAI as OpenAIClient } from "openai";
+import { OpenAIChat } from "@langchain/openai";
+
import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import { Generation, GenerationChunk, LLMResult } from "../schema/index.js";
-import {
- AzureOpenAIInput,
- OpenAICallOptions,
- OpenAIChatInput,
- OpenAICoreRequestOptions,
- LegacyOpenAIInput,
-} from "../types/openai-types.js";
-import { OpenAIEndpointConfig, getEndpoint } from "../util/azure.js";
+import type { Generation, LLMResult } from "../schema/index.js";
import { getEnvironmentVariable } from "../util/env.js";
import { promptLayerTrackRequest } from "../util/prompt-layer.js";
-import { BaseLLMParams, LLM } from "./base.js";
-import { wrapOpenAIClientError } from "../util/openai.js";
-
-export { type AzureOpenAIInput, type OpenAIChatInput };
-/**
- * Interface that extends the OpenAICallOptions interface and includes an
- * optional promptIndex property. It represents the options that can be
- * passed when making a call to the OpenAI Chat API.
- */
-export interface OpenAIChatCallOptions extends OpenAICallOptions {
- promptIndex?: number;
-}
-
-/**
- * Wrapper around OpenAI large language models that use the Chat endpoint.
- *
- * To use you should have the `openai` package installed, with the
- * `OPENAI_API_KEY` environment variable set.
- *
- * To use with Azure you should have the `openai` package installed, with the
- * `AZURE_OPENAI_API_KEY`,
- * `AZURE_OPENAI_API_INSTANCE_NAME`,
- * `AZURE_OPENAI_API_DEPLOYMENT_NAME`
- * and `AZURE_OPENAI_API_VERSION` environment variable set.
- *
- * @remarks
- * Any parameters that are valid to be passed to {@link
- * https://platform.openai.com/docs/api-reference/chat/create |
- * `openai.createCompletion`} can be passed through {@link modelKwargs}, even
- * if not explicitly available on this class.
- *
- * @augments BaseLLM
- * @augments OpenAIInput
- * @augments AzureOpenAIChatInput
- * @example
- * ```typescript
- * const model = new OpenAIChat({
- * prefixMessages: [
- * {
- * role: "system",
- * content: "You are a helpful assistant that answers in pirate language",
- * },
- * ],
- * maxTokens: 50,
- * });
- *
- * const res = await model.call(
- * "What would be a good company name for a company that makes colorful socks?"
- * );
- * console.log({ res });
- * ```
- */
-export class OpenAIChat
- extends LLM
- implements OpenAIChatInput, AzureOpenAIInput
-{
- static lc_name() {
- return "OpenAIChat";
- }
-
- get callKeys() {
- return [...super.callKeys, "options", "promptIndex"];
- }
-
- lc_serializable = true;
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- openAIApiKey: "OPENAI_API_KEY",
- azureOpenAIApiKey: "AZURE_OPENAI_API_KEY",
- organization: "OPENAI_ORGANIZATION",
- };
- }
-
- get lc_aliases(): Record {
- return {
- modelName: "model",
- openAIApiKey: "openai_api_key",
- azureOpenAIApiVersion: "azure_openai_api_version",
- azureOpenAIApiKey: "azure_openai_api_key",
- azureOpenAIApiInstanceName: "azure_openai_api_instance_name",
- azureOpenAIApiDeploymentName: "azure_openai_api_deployment_name",
- };
- }
-
- temperature = 1;
-
- topP = 1;
-
- frequencyPenalty = 0;
-
- presencePenalty = 0;
-
- n = 1;
-
- logitBias?: Record;
-
- maxTokens?: number;
-
- modelName = "gpt-3.5-turbo";
-
- prefixMessages?: OpenAIClient.Chat.ChatCompletionMessageParam[];
-
- modelKwargs?: OpenAIChatInput["modelKwargs"];
-
- timeout?: number;
-
- stop?: string[];
-
- user?: string;
-
- streaming = false;
-
- openAIApiKey?: string;
-
- azureOpenAIApiVersion?: string;
-
- azureOpenAIApiKey?: string;
-
- azureOpenAIApiInstanceName?: string;
-
- azureOpenAIApiDeploymentName?: string;
-
- azureOpenAIBasePath?: string;
-
- organization?: string;
-
- private client: OpenAIClient;
-
- private clientConfig: ClientOptions;
-
- constructor(
- fields?: Partial &
- Partial &
- BaseLLMParams & {
- configuration?: ClientOptions & LegacyOpenAIInput;
- },
- /** @deprecated */
- configuration?: ClientOptions & LegacyOpenAIInput
- ) {
- super(fields ?? {});
-
- this.openAIApiKey =
- fields?.openAIApiKey ?? getEnvironmentVariable("OPENAI_API_KEY");
-
- this.azureOpenAIApiKey =
- fields?.azureOpenAIApiKey ??
- getEnvironmentVariable("AZURE_OPENAI_API_KEY");
-
- if (!this.azureOpenAIApiKey && !this.openAIApiKey) {
- throw new Error("OpenAI or Azure OpenAI API key not found");
- }
-
- this.azureOpenAIApiInstanceName =
- fields?.azureOpenAIApiInstanceName ??
- getEnvironmentVariable("AZURE_OPENAI_API_INSTANCE_NAME");
-
- this.azureOpenAIApiDeploymentName =
- (fields?.azureOpenAIApiCompletionsDeploymentName ||
- fields?.azureOpenAIApiDeploymentName) ??
- (getEnvironmentVariable("AZURE_OPENAI_API_COMPLETIONS_DEPLOYMENT_NAME") ||
- getEnvironmentVariable("AZURE_OPENAI_API_DEPLOYMENT_NAME"));
-
- this.azureOpenAIApiVersion =
- fields?.azureOpenAIApiVersion ??
- getEnvironmentVariable("AZURE_OPENAI_API_VERSION");
-
- this.azureOpenAIBasePath =
- fields?.azureOpenAIBasePath ??
- getEnvironmentVariable("AZURE_OPENAI_BASE_PATH");
- this.organization =
- fields?.configuration?.organization ??
- getEnvironmentVariable("OPENAI_ORGANIZATION");
+export {
+ type AzureOpenAIInput,
+ type OpenAICallOptions,
+ type OpenAIInput,
+ type OpenAIChatCallOptions,
+} from "@langchain/openai";
- this.modelName = fields?.modelName ?? this.modelName;
- this.prefixMessages = fields?.prefixMessages ?? this.prefixMessages;
- this.modelKwargs = fields?.modelKwargs ?? {};
- this.timeout = fields?.timeout;
-
- this.temperature = fields?.temperature ?? this.temperature;
- this.topP = fields?.topP ?? this.topP;
- this.frequencyPenalty = fields?.frequencyPenalty ?? this.frequencyPenalty;
- this.presencePenalty = fields?.presencePenalty ?? this.presencePenalty;
- this.n = fields?.n ?? this.n;
- this.logitBias = fields?.logitBias;
- this.maxTokens = fields?.maxTokens;
- this.stop = fields?.stop;
- this.user = fields?.user;
-
- this.streaming = fields?.streaming ?? false;
-
- if (this.n > 1) {
- throw new Error(
- "Cannot use n > 1 in OpenAIChat LLM. Use ChatOpenAI Chat Model instead."
- );
- }
-
- if (this.azureOpenAIApiKey) {
- if (!this.azureOpenAIApiInstanceName && !this.azureOpenAIBasePath) {
- throw new Error("Azure OpenAI API instance name not found");
- }
- if (!this.azureOpenAIApiDeploymentName) {
- throw new Error("Azure OpenAI API deployment name not found");
- }
- if (!this.azureOpenAIApiVersion) {
- throw new Error("Azure OpenAI API version not found");
- }
- this.openAIApiKey = this.openAIApiKey ?? "";
- }
-
- this.clientConfig = {
- apiKey: this.openAIApiKey,
- organization: this.organization,
- baseURL: configuration?.basePath ?? fields?.configuration?.basePath,
- dangerouslyAllowBrowser: true,
- defaultHeaders:
- configuration?.baseOptions?.headers ??
- fields?.configuration?.baseOptions?.headers,
- defaultQuery:
- configuration?.baseOptions?.params ??
- fields?.configuration?.baseOptions?.params,
- ...configuration,
- ...fields?.configuration,
- };
- }
-
- /**
- * Get the parameters used to invoke the model
- */
- invocationParams(
- options?: this["ParsedCallOptions"]
- ): Omit {
- return {
- model: this.modelName,
- temperature: this.temperature,
- top_p: this.topP,
- frequency_penalty: this.frequencyPenalty,
- presence_penalty: this.presencePenalty,
- n: this.n,
- logit_bias: this.logitBias,
- max_tokens: this.maxTokens === -1 ? undefined : this.maxTokens,
- stop: options?.stop ?? this.stop,
- user: this.user,
- stream: this.streaming,
- ...this.modelKwargs,
- };
- }
-
- /** @ignore */
- _identifyingParams(): Omit<
- OpenAIClient.Chat.ChatCompletionCreateParams,
- "messages"
- > & {
- model_name: string;
- } & ClientOptions {
- return {
- model_name: this.modelName,
- ...this.invocationParams(),
- ...this.clientConfig,
- };
- }
-
- /**
- * Get the identifying parameters for the model
- */
- identifyingParams(): Omit<
- OpenAIClient.Chat.ChatCompletionCreateParams,
- "messages"
- > & {
- model_name: string;
- } & ClientOptions {
- return {
- model_name: this.modelName,
- ...this.invocationParams(),
- ...this.clientConfig,
- };
- }
-
- /**
- * Formats the messages for the OpenAI API.
- * @param prompt The prompt to be formatted.
- * @returns Array of formatted messages.
- */
- private formatMessages(
- prompt: string
- ): OpenAIClient.Chat.ChatCompletionMessageParam[] {
- const message: OpenAIClient.Chat.ChatCompletionMessageParam = {
- role: "user",
- content: prompt,
- };
- return this.prefixMessages ? [...this.prefixMessages, message] : [message];
- }
-
- async *_streamResponseChunks(
- prompt: string,
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): AsyncGenerator {
- const params = {
- ...this.invocationParams(options),
- messages: this.formatMessages(prompt),
- stream: true as const,
- };
- const stream = await this.completionWithRetry(params, options);
- for await (const data of stream) {
- const choice = data?.choices[0];
- if (!choice) {
- continue;
- }
- const { delta } = choice;
- const generationChunk = new GenerationChunk({
- text: delta.content ?? "",
- });
- yield generationChunk;
- const newTokenIndices = {
- prompt: options.promptIndex ?? 0,
- completion: choice.index ?? 0,
- };
- // eslint-disable-next-line no-void
- void runManager?.handleLLMNewToken(
- generationChunk.text ?? "",
- newTokenIndices
- );
- }
- if (options.signal?.aborted) {
- throw new Error("AbortError");
- }
- }
-
- /** @ignore */
- async _call(
- prompt: string,
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): Promise {
- const params = this.invocationParams(options);
-
- if (params.stream) {
- const stream = await this._streamResponseChunks(
- prompt,
- options,
- runManager
- );
- let finalChunk: GenerationChunk | undefined;
- for await (const chunk of stream) {
- if (finalChunk === undefined) {
- finalChunk = chunk;
- } else {
- finalChunk = finalChunk.concat(chunk);
- }
- }
- return finalChunk?.text ?? "";
- } else {
- const response = await this.completionWithRetry(
- {
- ...params,
- stream: false,
- messages: this.formatMessages(prompt),
- },
- {
- signal: options.signal,
- ...options.options,
- }
- );
- return response?.choices[0]?.message?.content ?? "";
- }
- }
-
- /**
- * Calls the OpenAI API with retry logic in case of failures.
- * @param request The request to send to the OpenAI API.
- * @param options Optional configuration for the API call.
- * @returns The response from the OpenAI API.
- */
- async completionWithRetry(
- request: OpenAIClient.Chat.ChatCompletionCreateParamsStreaming,
- options?: OpenAICoreRequestOptions
- ): Promise>;
-
- async completionWithRetry(
- request: OpenAIClient.Chat.ChatCompletionCreateParamsNonStreaming,
- options?: OpenAICoreRequestOptions
- ): Promise;
-
- async completionWithRetry(
- request:
- | OpenAIClient.Chat.ChatCompletionCreateParamsStreaming
- | OpenAIClient.Chat.ChatCompletionCreateParamsNonStreaming,
- options?: OpenAICoreRequestOptions
- ): Promise<
- | AsyncIterable
- | OpenAIClient.Chat.Completions.ChatCompletion
- > {
- const requestOptions = this._getClientOptions(options);
- return this.caller.call(async () => {
- try {
- const res = await this.client.chat.completions.create(
- request,
- requestOptions
- );
- return res;
- } catch (e) {
- const error = wrapOpenAIClientError(e);
- throw error;
- }
- });
- }
-
- /** @ignore */
- private _getClientOptions(options: OpenAICoreRequestOptions | undefined) {
- if (!this.client) {
- const openAIEndpointConfig: OpenAIEndpointConfig = {
- azureOpenAIApiDeploymentName: this.azureOpenAIApiDeploymentName,
- azureOpenAIApiInstanceName: this.azureOpenAIApiInstanceName,
- azureOpenAIApiKey: this.azureOpenAIApiKey,
- azureOpenAIBasePath: this.azureOpenAIBasePath,
- baseURL: this.clientConfig.baseURL,
- };
-
- const endpoint = getEndpoint(openAIEndpointConfig);
-
- const params = {
- ...this.clientConfig,
- baseURL: endpoint,
- timeout: this.timeout,
- maxRetries: 0,
- };
- if (!params.baseURL) {
- delete params.baseURL;
- }
-
- this.client = new OpenAIClient(params);
- }
- const requestOptions = {
- ...this.clientConfig,
- ...options,
- } as OpenAICoreRequestOptions;
- if (this.azureOpenAIApiKey) {
- requestOptions.headers = {
- "api-key": this.azureOpenAIApiKey,
- ...requestOptions.headers,
- };
- requestOptions.query = {
- "api-version": this.azureOpenAIApiVersion,
- ...requestOptions.query,
- };
- }
- return requestOptions;
- }
-
- _llmType() {
- return "openai";
- }
-}
+export { OpenAIChat };
/**
* PromptLayer wrapper to OpenAIChat
diff --git a/langchain/src/llms/openai.ts b/langchain/src/llms/openai.ts
index c962f30c096f..edfb429272b5 100644
--- a/langchain/src/llms/openai.ts
+++ b/langchain/src/llms/openai.ts
@@ -1,558 +1,17 @@
-import type { TiktokenModel } from "js-tiktoken/lite";
-import { type ClientOptions, OpenAI as OpenAIClient } from "openai";
-import { calculateMaxTokens } from "../base_language/count_tokens.js";
+import { OpenAI } from "@langchain/openai";
+
import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import { GenerationChunk, LLMResult } from "../schema/index.js";
-import {
- AzureOpenAIInput,
- OpenAICallOptions,
- OpenAICoreRequestOptions,
- OpenAIInput,
- LegacyOpenAIInput,
-} from "../types/openai-types.js";
-import { OpenAIEndpointConfig, getEndpoint } from "../util/azure.js";
-import { chunkArray } from "../util/chunk.js";
+import type { LLMResult } from "../schema/index.js";
import { getEnvironmentVariable } from "../util/env.js";
import { promptLayerTrackRequest } from "../util/prompt-layer.js";
-import { BaseLLM, BaseLLMParams } from "./base.js";
-import { OpenAIChat } from "./openai-chat.js";
-import { wrapOpenAIClientError } from "../util/openai.js";
-
-export type { AzureOpenAIInput, OpenAICallOptions, OpenAIInput };
-
-/**
- * Interface for tracking token usage in OpenAI calls.
- */
-interface TokenUsage {
- completionTokens?: number;
- promptTokens?: number;
- totalTokens?: number;
-}
-
-/**
- * Wrapper around OpenAI large language models.
- *
- * To use you should have the `openai` package installed, with the
- * `OPENAI_API_KEY` environment variable set.
- *
- * To use with Azure you should have the `openai` package installed, with the
- * `AZURE_OPENAI_API_KEY`,
- * `AZURE_OPENAI_API_INSTANCE_NAME`,
- * `AZURE_OPENAI_API_DEPLOYMENT_NAME`
- * and `AZURE_OPENAI_API_VERSION` environment variable set.
- *
- * @remarks
- * Any parameters that are valid to be passed to {@link
- * https://platform.openai.com/docs/api-reference/completions/create |
- * `openai.createCompletion`} can be passed through {@link modelKwargs}, even
- * if not explicitly available on this class.
- * @example
- * ```typescript
- * const model = new OpenAI({
- * modelName: "gpt-4",
- * temperature: 0.7,
- * maxTokens: 1000,
- * maxRetries: 5,
- * });
- *
- * const res = await model.call(
- * "Question: What would be a good company name for a company that makes colorful socks?\nAnswer:"
- * );
- * console.log({ res });
- * ```
- */
-export class OpenAI
- extends BaseLLM
- implements OpenAIInput, AzureOpenAIInput
-{
- static lc_name() {
- return "OpenAI";
- }
-
- get callKeys() {
- return [...super.callKeys, "options"];
- }
-
- lc_serializable = true;
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- openAIApiKey: "OPENAI_API_KEY",
- azureOpenAIApiKey: "AZURE_OPENAI_API_KEY",
- organization: "OPENAI_ORGANIZATION",
- };
- }
-
- get lc_aliases(): Record {
- return {
- modelName: "model",
- openAIApiKey: "openai_api_key",
- azureOpenAIApiVersion: "azure_openai_api_version",
- azureOpenAIApiKey: "azure_openai_api_key",
- azureOpenAIApiInstanceName: "azure_openai_api_instance_name",
- azureOpenAIApiDeploymentName: "azure_openai_api_deployment_name",
- };
- }
-
- temperature = 0.7;
-
- maxTokens = 256;
-
- topP = 1;
-
- frequencyPenalty = 0;
-
- presencePenalty = 0;
-
- n = 1;
-
- bestOf?: number;
-
- logitBias?: Record;
-
- modelName = "gpt-3.5-turbo-instruct";
-
- modelKwargs?: OpenAIInput["modelKwargs"];
-
- batchSize = 20;
-
- timeout?: number;
- stop?: string[];
+export {
+ type AzureOpenAIInput,
+ type OpenAICallOptions,
+ type OpenAIInput,
+} from "@langchain/openai";
- user?: string;
-
- streaming = false;
-
- openAIApiKey?: string;
-
- azureOpenAIApiVersion?: string;
-
- azureOpenAIApiKey?: string;
-
- azureOpenAIApiInstanceName?: string;
-
- azureOpenAIApiDeploymentName?: string;
-
- azureOpenAIBasePath?: string;
-
- organization?: string;
-
- private client: OpenAIClient;
-
- private clientConfig: ClientOptions;
-
- constructor(
- fields?: Partial &
- Partial &
- BaseLLMParams & {
- configuration?: ClientOptions & LegacyOpenAIInput;
- },
- /** @deprecated */
- configuration?: ClientOptions & LegacyOpenAIInput
- ) {
- if (
- (fields?.modelName?.startsWith("gpt-3.5-turbo") ||
- fields?.modelName?.startsWith("gpt-4")) &&
- !fields?.modelName?.includes("-instruct")
- ) {
- // eslint-disable-next-line no-constructor-return
- return new OpenAIChat(
- fields,
- configuration
- ) as unknown as OpenAI;
- }
- super(fields ?? {});
-
- this.openAIApiKey =
- fields?.openAIApiKey ?? getEnvironmentVariable("OPENAI_API_KEY");
-
- this.azureOpenAIApiKey =
- fields?.azureOpenAIApiKey ??
- getEnvironmentVariable("AZURE_OPENAI_API_KEY");
-
- if (!this.azureOpenAIApiKey && !this.openAIApiKey) {
- throw new Error("OpenAI or Azure OpenAI API key not found");
- }
-
- this.azureOpenAIApiInstanceName =
- fields?.azureOpenAIApiInstanceName ??
- getEnvironmentVariable("AZURE_OPENAI_API_INSTANCE_NAME");
-
- this.azureOpenAIApiDeploymentName =
- (fields?.azureOpenAIApiCompletionsDeploymentName ||
- fields?.azureOpenAIApiDeploymentName) ??
- (getEnvironmentVariable("AZURE_OPENAI_API_COMPLETIONS_DEPLOYMENT_NAME") ||
- getEnvironmentVariable("AZURE_OPENAI_API_DEPLOYMENT_NAME"));
-
- this.azureOpenAIApiVersion =
- fields?.azureOpenAIApiVersion ??
- getEnvironmentVariable("AZURE_OPENAI_API_VERSION");
-
- this.azureOpenAIBasePath =
- fields?.azureOpenAIBasePath ??
- getEnvironmentVariable("AZURE_OPENAI_BASE_PATH");
-
- this.organization =
- fields?.configuration?.organization ??
- getEnvironmentVariable("OPENAI_ORGANIZATION");
-
- this.modelName = fields?.modelName ?? this.modelName;
- this.modelKwargs = fields?.modelKwargs ?? {};
- this.batchSize = fields?.batchSize ?? this.batchSize;
- this.timeout = fields?.timeout;
-
- this.temperature = fields?.temperature ?? this.temperature;
- this.maxTokens = fields?.maxTokens ?? this.maxTokens;
- this.topP = fields?.topP ?? this.topP;
- this.frequencyPenalty = fields?.frequencyPenalty ?? this.frequencyPenalty;
- this.presencePenalty = fields?.presencePenalty ?? this.presencePenalty;
- this.n = fields?.n ?? this.n;
- this.bestOf = fields?.bestOf ?? this.bestOf;
- this.logitBias = fields?.logitBias;
- this.stop = fields?.stop;
- this.user = fields?.user;
-
- this.streaming = fields?.streaming ?? false;
-
- if (this.streaming && this.bestOf && this.bestOf > 1) {
- throw new Error("Cannot stream results when bestOf > 1");
- }
-
- if (this.azureOpenAIApiKey) {
- if (!this.azureOpenAIApiInstanceName && !this.azureOpenAIBasePath) {
- throw new Error("Azure OpenAI API instance name not found");
- }
- if (!this.azureOpenAIApiDeploymentName) {
- throw new Error("Azure OpenAI API deployment name not found");
- }
- if (!this.azureOpenAIApiVersion) {
- throw new Error("Azure OpenAI API version not found");
- }
- this.openAIApiKey = this.openAIApiKey ?? "";
- }
-
- this.clientConfig = {
- apiKey: this.openAIApiKey,
- organization: this.organization,
- baseURL: configuration?.basePath ?? fields?.configuration?.basePath,
- dangerouslyAllowBrowser: true,
- defaultHeaders:
- configuration?.baseOptions?.headers ??
- fields?.configuration?.baseOptions?.headers,
- defaultQuery:
- configuration?.baseOptions?.params ??
- fields?.configuration?.baseOptions?.params,
- ...configuration,
- ...fields?.configuration,
- };
- }
-
- /**
- * Get the parameters used to invoke the model
- */
- invocationParams(
- options?: this["ParsedCallOptions"]
- ): Omit {
- return {
- model: this.modelName,
- temperature: this.temperature,
- max_tokens: this.maxTokens,
- top_p: this.topP,
- frequency_penalty: this.frequencyPenalty,
- presence_penalty: this.presencePenalty,
- n: this.n,
- best_of: this.bestOf,
- logit_bias: this.logitBias,
- stop: options?.stop ?? this.stop,
- user: this.user,
- stream: this.streaming,
- ...this.modelKwargs,
- };
- }
-
- /** @ignore */
- _identifyingParams(): Omit & {
- model_name: string;
- } & ClientOptions {
- return {
- model_name: this.modelName,
- ...this.invocationParams(),
- ...this.clientConfig,
- };
- }
-
- /**
- * Get the identifying parameters for the model
- */
- identifyingParams(): Omit & {
- model_name: string;
- } & ClientOptions {
- return this._identifyingParams();
- }
-
- /**
- * Call out to OpenAI's endpoint with k unique prompts
- *
- * @param [prompts] - The prompts to pass into the model.
- * @param [options] - Optional list of stop words to use when generating.
- * @param [runManager] - Optional callback manager to use when generating.
- *
- * @returns The full LLM output.
- *
- * @example
- * ```ts
- * import { OpenAI } from "langchain/llms/openai";
- * const openai = new OpenAI();
- * const response = await openai.generate(["Tell me a joke."]);
- * ```
- */
- async _generate(
- prompts: string[],
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): Promise {
- const subPrompts = chunkArray(prompts, this.batchSize);
- const choices: OpenAIClient.CompletionChoice[] = [];
- const tokenUsage: TokenUsage = {};
-
- const params = this.invocationParams(options);
-
- if (params.max_tokens === -1) {
- if (prompts.length !== 1) {
- throw new Error(
- "max_tokens set to -1 not supported for multiple inputs"
- );
- }
- params.max_tokens = await calculateMaxTokens({
- prompt: prompts[0],
- // Cast here to allow for other models that may not fit the union
- modelName: this.modelName as TiktokenModel,
- });
- }
-
- for (let i = 0; i < subPrompts.length; i += 1) {
- const data = params.stream
- ? await (async () => {
- const choices: OpenAIClient.CompletionChoice[] = [];
- let response: Omit | undefined;
- const stream = await this.completionWithRetry(
- {
- ...params,
- stream: true,
- prompt: subPrompts[i],
- },
- options
- );
- for await (const message of stream) {
- // on the first message set the response properties
- if (!response) {
- response = {
- id: message.id,
- object: message.object,
- created: message.created,
- model: message.model,
- };
- }
-
- // on all messages, update choice
- for (const part of message.choices) {
- if (!choices[part.index]) {
- choices[part.index] = part;
- } else {
- const choice = choices[part.index];
- choice.text += part.text;
- choice.finish_reason = part.finish_reason;
- choice.logprobs = part.logprobs;
- }
- void runManager?.handleLLMNewToken(part.text, {
- prompt: Math.floor(part.index / this.n),
- completion: part.index % this.n,
- });
- }
- }
- if (options.signal?.aborted) {
- throw new Error("AbortError");
- }
- return { ...response, choices };
- })()
- : await this.completionWithRetry(
- {
- ...params,
- stream: false,
- prompt: subPrompts[i],
- },
- {
- signal: options.signal,
- ...options.options,
- }
- );
-
- choices.push(...data.choices);
- const {
- completion_tokens: completionTokens,
- prompt_tokens: promptTokens,
- total_tokens: totalTokens,
- } = data.usage
- ? data.usage
- : {
- completion_tokens: undefined,
- prompt_tokens: undefined,
- total_tokens: undefined,
- };
-
- if (completionTokens) {
- tokenUsage.completionTokens =
- (tokenUsage.completionTokens ?? 0) + completionTokens;
- }
-
- if (promptTokens) {
- tokenUsage.promptTokens = (tokenUsage.promptTokens ?? 0) + promptTokens;
- }
-
- if (totalTokens) {
- tokenUsage.totalTokens = (tokenUsage.totalTokens ?? 0) + totalTokens;
- }
- }
-
- const generations = chunkArray(choices, this.n).map((promptChoices) =>
- promptChoices.map((choice) => ({
- text: choice.text ?? "",
- generationInfo: {
- finishReason: choice.finish_reason,
- logprobs: choice.logprobs,
- },
- }))
- );
- return {
- generations,
- llmOutput: { tokenUsage },
- };
- }
-
- // TODO(jacoblee): Refactor with _generate(..., {stream: true}) implementation?
- async *_streamResponseChunks(
- input: string,
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): AsyncGenerator {
- const params = {
- ...this.invocationParams(options),
- prompt: input,
- stream: true as const,
- };
- const stream = await this.completionWithRetry(params, options);
- for await (const data of stream) {
- const choice = data?.choices[0];
- if (!choice) {
- continue;
- }
- const chunk = new GenerationChunk({
- text: choice.text,
- generationInfo: {
- finishReason: choice.finish_reason,
- },
- });
- yield chunk;
- // eslint-disable-next-line no-void
- void runManager?.handleLLMNewToken(chunk.text ?? "");
- }
- if (options.signal?.aborted) {
- throw new Error("AbortError");
- }
- }
-
- /**
- * Calls the OpenAI API with retry logic in case of failures.
- * @param request The request to send to the OpenAI API.
- * @param options Optional configuration for the API call.
- * @returns The response from the OpenAI API.
- */
- async completionWithRetry(
- request: OpenAIClient.CompletionCreateParamsStreaming,
- options?: OpenAICoreRequestOptions
- ): Promise>;
-
- async completionWithRetry(
- request: OpenAIClient.CompletionCreateParamsNonStreaming,
- options?: OpenAICoreRequestOptions
- ): Promise;
-
- async completionWithRetry(
- request:
- | OpenAIClient.CompletionCreateParamsStreaming
- | OpenAIClient.CompletionCreateParamsNonStreaming,
- options?: OpenAICoreRequestOptions
- ): Promise<
- AsyncIterable | OpenAIClient.Completions.Completion
- > {
- const requestOptions = this._getClientOptions(options);
- return this.caller.call(async () => {
- try {
- const res = await this.client.completions.create(
- request,
- requestOptions
- );
- return res;
- } catch (e) {
- const error = wrapOpenAIClientError(e);
- throw error;
- }
- });
- }
-
- /**
- * Calls the OpenAI API with retry logic in case of failures.
- * @param request The request to send to the OpenAI API.
- * @param options Optional configuration for the API call.
- * @returns The response from the OpenAI API.
- */
- private _getClientOptions(options: OpenAICoreRequestOptions | undefined) {
- if (!this.client) {
- const openAIEndpointConfig: OpenAIEndpointConfig = {
- azureOpenAIApiDeploymentName: this.azureOpenAIApiDeploymentName,
- azureOpenAIApiInstanceName: this.azureOpenAIApiInstanceName,
- azureOpenAIApiKey: this.azureOpenAIApiKey,
- azureOpenAIBasePath: this.azureOpenAIBasePath,
- baseURL: this.clientConfig.baseURL,
- };
-
- const endpoint = getEndpoint(openAIEndpointConfig);
-
- const params = {
- ...this.clientConfig,
- baseURL: endpoint,
- timeout: this.timeout,
- maxRetries: 0,
- };
-
- if (!params.baseURL) {
- delete params.baseURL;
- }
-
- this.client = new OpenAIClient(params);
- }
- const requestOptions = {
- ...this.clientConfig,
- ...options,
- } as OpenAICoreRequestOptions;
- if (this.azureOpenAIApiKey) {
- requestOptions.headers = {
- "api-key": this.azureOpenAIApiKey,
- ...requestOptions.headers,
- };
- requestOptions.query = {
- "api-version": this.azureOpenAIApiVersion,
- ...requestOptions.query,
- };
- }
- return requestOptions;
- }
-
- _llmType() {
- return "openai";
- }
-}
+export { OpenAI };
/**
* PromptLayer wrapper to OpenAI
diff --git a/langchain/src/llms/portkey.ts b/langchain/src/llms/portkey.ts
index c6a2df313826..79b975e5fabc 100644
--- a/langchain/src/llms/portkey.ts
+++ b/langchain/src/llms/portkey.ts
@@ -1,179 +1 @@
-import _ from "lodash";
-import { LLMOptions, Portkey as _Portkey } from "portkey-ai";
-import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import { GenerationChunk, LLMResult } from "../schema/index.js";
-import { getEnvironmentVariable } from "../util/env.js";
-import { BaseLLM } from "./base.js";
-
-interface PortkeyOptions {
- apiKey?: string;
- baseURL?: string;
- mode?: string;
- llms?: [LLMOptions] | null;
-}
-
-const readEnv = (env: string, default_val?: string): string | undefined =>
- getEnvironmentVariable(env) ?? default_val;
-
-export class PortkeySession {
- portkey: _Portkey;
-
- constructor(options: PortkeyOptions = {}) {
- if (!options.apiKey) {
- /* eslint-disable no-param-reassign */
- options.apiKey = readEnv("PORTKEY_API_KEY");
- }
-
- if (!options.baseURL) {
- /* eslint-disable no-param-reassign */
- options.baseURL = readEnv("PORTKEY_BASE_URL", "https://api.portkey.ai");
- }
-
- this.portkey = new _Portkey({});
- this.portkey.llms = [{}];
- if (!options.apiKey) {
- throw new Error("Set Portkey ApiKey in PORTKEY_API_KEY env variable");
- }
-
- this.portkey = new _Portkey(options);
- }
-}
-
-const defaultPortkeySession: {
- session: PortkeySession;
- options: PortkeyOptions;
-}[] = [];
-
-/**
- * Get a session for the Portkey API. If one already exists with the same options,
- * it will be returned. Otherwise, a new session will be created.
- * @param options
- * @returns
- */
-export function getPortkeySession(options: PortkeyOptions = {}) {
- let session = defaultPortkeySession.find((session) =>
- _.isEqual(session.options, options)
- )?.session;
-
- if (!session) {
- session = new PortkeySession(options);
- defaultPortkeySession.push({ session, options });
- }
- return session;
-}
-
-/**
- * @example
- * ```typescript
- * const model = new Portkey({
- * mode: "single",
- * llms: [
- * {
- * provider: "openai",
- * virtual_key: "open-ai-key-1234",
- * model: "text-davinci-003",
- * max_tokens: 2000,
- * },
- * ],
- * });
- *
- * // Stream the output of the model and process it
- * const res = await model.stream(
- * "Question: Write a story about a king\nAnswer:"
- * );
- * for await (const i of res) {
- * process.stdout.write(i);
- * }
- * ```
- */
-export class Portkey extends BaseLLM {
- apiKey?: string = undefined;
-
- baseURL?: string = undefined;
-
- mode?: string = undefined;
-
- llms?: [LLMOptions] | null = undefined;
-
- session: PortkeySession;
-
- constructor(init?: Partial) {
- super(init ?? {});
- this.apiKey = init?.apiKey;
-
- this.baseURL = init?.baseURL;
-
- this.mode = init?.mode;
-
- this.llms = init?.llms;
-
- this.session = getPortkeySession({
- apiKey: this.apiKey,
- baseURL: this.baseURL,
- llms: this.llms,
- mode: this.mode,
- });
- }
-
- _llmType() {
- return "portkey";
- }
-
- async _generate(
- prompts: string[],
- options: this["ParsedCallOptions"],
- _?: CallbackManagerForLLMRun
- ): Promise {
- const choices = [];
- for (let i = 0; i < prompts.length; i += 1) {
- const response = await this.session.portkey.completions.create({
- prompt: prompts[i],
- ...options,
- stream: false,
- });
- choices.push(response.choices);
- }
- const generations = choices.map((promptChoices) =>
- promptChoices.map((choice) => ({
- text: choice.text ?? "",
- generationInfo: {
- finishReason: choice.finish_reason,
- logprobs: choice.logprobs,
- },
- }))
- );
-
- return {
- generations,
- };
- }
-
- async *_streamResponseChunks(
- input: string,
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): AsyncGenerator {
- const response = await this.session.portkey.completions.create({
- prompt: input,
- ...options,
- stream: true,
- });
- for await (const data of response) {
- const choice = data?.choices[0];
- if (!choice) {
- continue;
- }
- const chunk = new GenerationChunk({
- text: choice.text ?? "",
- generationInfo: {
- finishReason: choice.finish_reason,
- },
- });
- yield chunk;
- void runManager?.handleLLMNewToken(chunk.text ?? "");
- }
- if (options.signal?.aborted) {
- throw new Error("AbortError");
- }
- }
-}
+export * from "@langchain/community/llms/portkey";
diff --git a/langchain/src/llms/raycast.ts b/langchain/src/llms/raycast.ts
index 7901f0fde238..a36430dc3817 100644
--- a/langchain/src/llms/raycast.ts
+++ b/langchain/src/llms/raycast.ts
@@ -1,99 +1 @@
-import { AI, environment } from "@raycast/api";
-import { LLM, BaseLLMParams } from "./base.js";
-
-/**
- * The input parameters for the RaycastAI class, which extends the BaseLLMParams interface.
- */
-export interface RaycastAIInput extends BaseLLMParams {
- model?: AI.Model;
- creativity?: number;
- rateLimitPerMinute?: number;
-}
-
-const wait = (ms: number) =>
- new Promise((resolve) => {
- setTimeout(resolve, ms);
- });
-
-/**
- * The RaycastAI class, which extends the LLM class and implements the RaycastAIInput interface.
- */
-export class RaycastAI extends LLM implements RaycastAIInput {
- /**
- * The model to use for generating text.
- */
- model: AI.Model;
-
- /**
- * The creativity parameter, also known as the "temperature".
- */
- creativity: number;
-
- /**
- * The rate limit for API calls, in requests per minute.
- */
- rateLimitPerMinute: number;
-
- /**
- * The timestamp of the last API call, used to enforce the rate limit.
- */
- private lastCallTimestamp = 0;
-
- /**
- * Creates a new instance of the RaycastAI class.
- * @param {RaycastAIInput} fields The input parameters for the RaycastAI class.
- * @throws {Error} If the Raycast AI environment is not accessible.
- */
- constructor(fields: RaycastAIInput) {
- super(fields ?? {});
-
- if (!environment.canAccess(AI)) {
- throw new Error("Raycast AI environment is not accessible.");
- }
-
- this.model = fields.model ?? "text-davinci-003";
- this.creativity = fields.creativity ?? 0.5;
- this.rateLimitPerMinute = fields.rateLimitPerMinute ?? 10;
- }
-
- /**
- * Returns the type of the LLM, which is "raycast_ai".
- * @return {string} The type of the LLM.
- * @ignore
- */
- _llmType() {
- return "raycast_ai";
- }
-
- /**
- * Calls AI.ask with the given prompt and returns the generated text.
- * @param {string} prompt The prompt to generate text from.
- * @return {Promise} A Promise that resolves to the generated text.
- * @ignore
- */
- async _call(
- prompt: string,
- options: this["ParsedCallOptions"]
- ): Promise {
- const response = await this.caller.call(async () => {
- // Rate limit calls to Raycast AI
- const now = Date.now();
- const timeSinceLastCall = now - this.lastCallTimestamp;
- const timeToWait =
- (60 / this.rateLimitPerMinute) * 1000 - timeSinceLastCall;
-
- if (timeToWait > 0) {
- await wait(timeToWait);
- }
-
- return await AI.ask(prompt, {
- model: this.model,
- creativity: this.creativity,
- signal: options.signal,
- });
- });
-
- // Since Raycast AI returns the response directly, no need for output transformation
- return response;
- }
-}
+export * from "@langchain/community/llms/raycast";
diff --git a/langchain/src/llms/replicate.ts b/langchain/src/llms/replicate.ts
index 27fa66c5eb7c..72c1ca24a637 100644
--- a/langchain/src/llms/replicate.ts
+++ b/langchain/src/llms/replicate.ts
@@ -1,158 +1 @@
-import { getEnvironmentVariable } from "../util/env.js";
-import { LLM, BaseLLMParams } from "./base.js";
-
-/**
- * Interface defining the structure of the input data for the Replicate
- * class. It includes details about the model to be used, any additional
- * input parameters, and the API key for the Replicate service.
- */
-export interface ReplicateInput {
- // owner/model_name:version
- model: `${string}/${string}:${string}`;
-
- input?: {
- // different models accept different inputs
- [key: string]: string | number | boolean;
- };
-
- apiKey?: string;
-
- /** The key used to pass prompts to the model. */
- promptKey?: string;
-}
-
-/**
- * Class responsible for managing the interaction with the Replicate API.
- * It handles the API key and model details, makes the actual API calls,
- * and converts the API response into a format usable by the rest of the
- * LangChain framework.
- * @example
- * ```typescript
- * const model = new Replicate({
- * model: "replicate/flan-t5-xl:3ae0799123a1fe11f8c89fd99632f843fc5f7a761630160521c4253149754523",
- * });
- *
- * const res = await model.call(
- * "Question: What would be a good company name for a company that makes colorful socks?\nAnswer:"
- * );
- * console.log({ res });
- * ```
- */
-export class Replicate extends LLM implements ReplicateInput {
- static lc_name() {
- return "Replicate";
- }
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- apiKey: "REPLICATE_API_TOKEN",
- };
- }
-
- lc_serializable = true;
-
- model: ReplicateInput["model"];
-
- input: ReplicateInput["input"];
-
- apiKey: string;
-
- promptKey?: string;
-
- constructor(fields: ReplicateInput & BaseLLMParams) {
- super(fields);
-
- const apiKey =
- fields?.apiKey ??
- getEnvironmentVariable("REPLICATE_API_KEY") ?? // previous environment variable for backwards compatibility
- getEnvironmentVariable("REPLICATE_API_TOKEN"); // current environment variable, matching the Python library
-
- if (!apiKey) {
- throw new Error(
- "Please set the REPLICATE_API_TOKEN environment variable"
- );
- }
-
- this.apiKey = apiKey;
- this.model = fields.model;
- this.input = fields.input ?? {};
- this.promptKey = fields.promptKey;
- }
-
- _llmType() {
- return "replicate";
- }
-
- /** @ignore */
- async _call(
- prompt: string,
- options: this["ParsedCallOptions"]
- ): Promise {
- const imports = await Replicate.imports();
-
- const replicate = new imports.Replicate({
- userAgent: "langchain",
- auth: this.apiKey,
- });
-
- if (this.promptKey === undefined) {
- const [modelString, versionString] = this.model.split(":");
- const version = await replicate.models.versions.get(
- modelString.split("/")[0],
- modelString.split("/")[1],
- versionString
- );
- const openapiSchema = version.openapi_schema;
- const inputProperties: { "x-order": number | undefined }[] =
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- (openapiSchema as any)?.components?.schemas?.Input?.properties;
- if (inputProperties === undefined) {
- this.promptKey = "prompt";
- } else {
- const sortedInputProperties = Object.entries(inputProperties).sort(
- ([_keyA, valueA], [_keyB, valueB]) => {
- const orderA = valueA["x-order"] || 0;
- const orderB = valueB["x-order"] || 0;
- return orderA - orderB;
- }
- );
- this.promptKey = sortedInputProperties[0][0] ?? "prompt";
- }
- }
- const output = await this.caller.callWithOptions(
- { signal: options.signal },
- () =>
- replicate.run(this.model, {
- input: {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- [this.promptKey!]: prompt,
- ...this.input,
- },
- })
- );
-
- if (typeof output === "string") {
- return output;
- } else if (Array.isArray(output)) {
- return output.join("");
- } else {
- // Note this is a little odd, but the output format is not consistent
- // across models, so it makes some amount of sense.
- return String(output);
- }
- }
-
- /** @ignore */
- static async imports(): Promise<{
- Replicate: typeof import("replicate").default;
- }> {
- try {
- const { default: Replicate } = await import("replicate");
- return { Replicate };
- } catch (e) {
- throw new Error(
- "Please install replicate as a dependency with, e.g. `yarn add replicate`"
- );
- }
- }
-}
+export * from "@langchain/community/llms/replicate";
diff --git a/langchain/src/llms/sagemaker_endpoint.ts b/langchain/src/llms/sagemaker_endpoint.ts
index 38706d608417..f9a5e590c0fb 100644
--- a/langchain/src/llms/sagemaker_endpoint.ts
+++ b/langchain/src/llms/sagemaker_endpoint.ts
@@ -1,283 +1 @@
-import {
- InvokeEndpointCommand,
- InvokeEndpointWithResponseStreamCommand,
- SageMakerRuntimeClient,
- SageMakerRuntimeClientConfig,
-} from "@aws-sdk/client-sagemaker-runtime";
-import { CallbackManagerForLLMRun } from "../callbacks/manager.js";
-import { GenerationChunk } from "../schema/index.js";
-import { BaseLLMCallOptions, BaseLLMParams, LLM } from "./base.js";
-
-/**
- * A handler class to transform input from LLM to a format that SageMaker
- * endpoint expects. Similarily, the class also handles transforming output from
- * the SageMaker endpoint to a format that LLM class expects.
- *
- * Example:
- * ```
- * class ContentHandler implements ContentHandlerBase {
- * contentType = "application/json"
- * accepts = "application/json"
- *
- * transformInput(prompt: string, modelKwargs: Record) {
- * const inputString = JSON.stringify({
- * prompt,
- * ...modelKwargs
- * })
- * return Buffer.from(inputString)
- * }
- *
- * transformOutput(output: Uint8Array) {
- * const responseJson = JSON.parse(Buffer.from(output).toString("utf-8"))
- * return responseJson[0].generated_text
- * }
- *
- * }
- * ```
- */
-export abstract class BaseSageMakerContentHandler {
- contentType = "text/plain";
-
- accepts = "text/plain";
-
- /**
- * Transforms the prompt and model arguments into a specific format for sending to SageMaker.
- * @param {InputType} prompt The prompt to be transformed.
- * @param {Record} modelKwargs Additional arguments.
- * @returns {Promise} A promise that resolves to the formatted data for sending.
- */
- abstract transformInput(
- prompt: InputType,
- modelKwargs: Record
- ): Promise;
-
- /**
- * Transforms SageMaker output into a desired format.
- * @param {Uint8Array} output The raw output from SageMaker.
- * @returns {Promise} A promise that resolves to the transformed data.
- */
- abstract transformOutput(output: Uint8Array): Promise;
-}
-
-export type SageMakerLLMContentHandler = BaseSageMakerContentHandler<
- string,
- string
->;
-
-/**
- * The SageMakerEndpointInput interface defines the input parameters for
- * the SageMakerEndpoint class, which includes the endpoint name, client
- * options for the SageMaker client, the content handler, and optional
- * keyword arguments for the model and the endpoint.
- */
-export interface SageMakerEndpointInput extends BaseLLMParams {
- /**
- * The name of the endpoint from the deployed SageMaker model. Must be unique
- * within an AWS Region.
- */
- endpointName: string;
- /**
- * Options passed to the SageMaker client.
- */
- clientOptions: SageMakerRuntimeClientConfig;
- /**
- * Key word arguments to pass to the model.
- */
- modelKwargs?: Record;
- /**
- * Optional attributes passed to the InvokeEndpointCommand
- */
- endpointKwargs?: Record;
- /**
- * The content handler class that provides an input and output transform
- * functions to handle formats between LLM and the endpoint.
- */
- contentHandler: SageMakerLLMContentHandler;
- streaming?: boolean;
-}
-
-/**
- * The SageMakerEndpoint class is used to interact with SageMaker
- * Inference Endpoint models. It uses the AWS client for authentication,
- * which automatically loads credentials.
- * If a specific credential profile is to be used, the name of the profile
- * from the ~/.aws/credentials file must be passed. The credentials or
- * roles used should have the required policies to access the SageMaker
- * endpoint.
- */
-export class SageMakerEndpoint extends LLM {
- static lc_name() {
- return "SageMakerEndpoint";
- }
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- "clientOptions.credentials.accessKeyId": "AWS_ACCESS_KEY_ID",
- "clientOptions.credentials.secretAccessKey": "AWS_SECRET_ACCESS_KEY",
- "clientOptions.credentials.sessionToken": "AWS_SESSION_TOKEN",
- };
- }
-
- endpointName: string;
-
- modelKwargs?: Record;
-
- endpointKwargs?: Record;
-
- client: SageMakerRuntimeClient;
-
- contentHandler: SageMakerLLMContentHandler;
-
- streaming: boolean;
-
- constructor(fields: SageMakerEndpointInput) {
- super(fields);
-
- if (!fields.clientOptions.region) {
- throw new Error(
- `Please pass a "clientOptions" object with a "region" field to the constructor`
- );
- }
-
- const endpointName = fields?.endpointName;
- if (!endpointName) {
- throw new Error(`Please pass an "endpointName" field to the constructor`);
- }
-
- const contentHandler = fields?.contentHandler;
- if (!contentHandler) {
- throw new Error(
- `Please pass a "contentHandler" field to the constructor`
- );
- }
-
- this.endpointName = fields.endpointName;
- this.contentHandler = fields.contentHandler;
- this.endpointKwargs = fields.endpointKwargs;
- this.modelKwargs = fields.modelKwargs;
- this.streaming = fields.streaming ?? false;
- this.client = new SageMakerRuntimeClient(fields.clientOptions);
- }
-
- _llmType() {
- return "sagemaker_endpoint";
- }
-
- /**
- * Calls the SageMaker endpoint and retrieves the result.
- * @param {string} prompt The input prompt.
- * @param {this["ParsedCallOptions"]} options Parsed call options.
- * @param {CallbackManagerForLLMRun} runManager Optional run manager.
- * @returns {Promise} A promise that resolves to the generated string.
- */
- /** @ignore */
- async _call(
- prompt: string,
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): Promise {
- return this.streaming
- ? await this.streamingCall(prompt, options, runManager)
- : await this.noStreamingCall(prompt, options);
- }
-
- private async streamingCall(
- prompt: string,
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): Promise {
- const chunks = [];
- for await (const chunk of this._streamResponseChunks(
- prompt,
- options,
- runManager
- )) {
- chunks.push(chunk.text);
- }
- return chunks.join("");
- }
-
- private async noStreamingCall(
- prompt: string,
- options: this["ParsedCallOptions"]
- ): Promise {
- const body = await this.contentHandler.transformInput(
- prompt,
- this.modelKwargs ?? {}
- );
- const { contentType, accepts } = this.contentHandler;
-
- const response = await this.caller.call(() =>
- this.client.send(
- new InvokeEndpointCommand({
- EndpointName: this.endpointName,
- Body: body,
- ContentType: contentType,
- Accept: accepts,
- ...this.endpointKwargs,
- }),
- { abortSignal: options.signal }
- )
- );
-
- if (response.Body === undefined) {
- throw new Error("Inference result missing Body");
- }
- return this.contentHandler.transformOutput(response.Body);
- }
-
- /**
- * Streams response chunks from the SageMaker endpoint.
- * @param {string} prompt The input prompt.
- * @param {this["ParsedCallOptions"]} options Parsed call options.
- * @returns {AsyncGenerator} An asynchronous generator yielding generation chunks.
- */
- async *_streamResponseChunks(
- prompt: string,
- options: this["ParsedCallOptions"],
- runManager?: CallbackManagerForLLMRun
- ): AsyncGenerator {
- const body = await this.contentHandler.transformInput(
- prompt,
- this.modelKwargs ?? {}
- );
- const { contentType, accepts } = this.contentHandler;
-
- const stream = await this.caller.call(() =>
- this.client.send(
- new InvokeEndpointWithResponseStreamCommand({
- EndpointName: this.endpointName,
- Body: body,
- ContentType: contentType,
- Accept: accepts,
- ...this.endpointKwargs,
- }),
- { abortSignal: options.signal }
- )
- );
-
- if (!stream.Body) {
- throw new Error("Inference result missing Body");
- }
-
- for await (const chunk of stream.Body) {
- if (chunk.PayloadPart && chunk.PayloadPart.Bytes) {
- const text = await this.contentHandler.transformOutput(
- chunk.PayloadPart.Bytes
- );
- yield new GenerationChunk({
- text,
- generationInfo: {
- ...chunk,
- response: undefined,
- },
- });
- await runManager?.handleLLMNewToken(text);
- } else if (chunk.InternalStreamFailure) {
- throw new Error(chunk.InternalStreamFailure.message);
- } else if (chunk.ModelStreamError) {
- throw new Error(chunk.ModelStreamError.message);
- }
- }
- }
-}
+export * from "@langchain/community/llms/sagemaker_endpoint";
diff --git a/langchain/src/llms/watsonx_ai.ts b/langchain/src/llms/watsonx_ai.ts
index dca510ba21c1..741308ef5ffb 100644
--- a/langchain/src/llms/watsonx_ai.ts
+++ b/langchain/src/llms/watsonx_ai.ts
@@ -1,194 +1 @@
-import { BaseLLMCallOptions, BaseLLMParams, LLM } from "./base.js";
-import { getEnvironmentVariable } from "../util/env.js";
-
-/**
- * The WatsonxAIParams interface defines the input parameters for
- * the WatsonxAI class.
- */
-export interface WatsonxAIParams extends BaseLLMParams {
- /**
- * WatsonX AI Complete Endpoint.
- * Can be used if you want a fully custom endpoint.
- */
- endpoint?: string;
- /**
- * IBM Cloud Compute Region.
- * eg. us-south, us-east, etc.
- */
- region?: string;
- /**
- * WatsonX AI Version.
- * Date representing the WatsonX AI Version.
- * eg. 2023-05-29
- */
- version?: string;
- /**
- * WatsonX AI Key.
- * Provide API Key if you do not wish to automatically pull from env.
- */
- ibmCloudApiKey?: string;
- /**
- * WatsonX AI Key.
- * Provide API Key if you do not wish to automatically pull from env.
- */
- projectId?: string;
- /**
- * Parameters accepted by the WatsonX AI Endpoint.
- */
- modelParameters?: Record;
- /**
- * WatsonX AI Model ID.
- */
- modelId?: string;
-}
-
-const endpointConstructor = (region: string, version: string) =>
- `https://${region}.ml.cloud.ibm.com/ml/v1-beta/generation/text?version=${version}`;
-
-/**
- * The WatsonxAI class is used to interact with Watsonx AI
- * Inference Endpoint models. It uses IBM Cloud for authentication.
- * This requires your IBM Cloud API Key which is autoloaded if not specified.
- */
-
-export class WatsonxAI extends LLM {
- static lc_name() {
- return "WatsonxAI";
- }
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- ibmCloudApiKey: "IBM_CLOUD_API_KEY",
- projectId: "WATSONX_PROJECT_ID",
- };
- }
-
- endpoint: string;
-
- region = "us-south";
-
- version = "2023-05-29";
-
- modelId = "meta-llama/llama-2-70b-chat";
-
- modelKwargs?: Record;
-
- ibmCloudApiKey?: string;
-
- ibmCloudToken?: string;
-
- ibmCloudTokenExpiresAt?: number;
-
- projectId?: string;
-
- modelParameters?: Record;
-
- constructor(fields: WatsonxAIParams) {
- super(fields);
-
- this.region = fields?.region ?? this.region;
- this.version = fields?.version ?? this.version;
- this.modelId = fields?.modelId ?? this.modelId;
- this.ibmCloudApiKey =
- fields?.ibmCloudApiKey ?? getEnvironmentVariable("IBM_CLOUD_API_KEY");
- this.projectId =
- fields?.projectId ?? getEnvironmentVariable("WATSONX_PROJECT_ID");
-
- this.endpoint =
- fields?.endpoint ?? endpointConstructor(this.region, this.version);
- this.modelParameters = fields.modelParameters;
-
- if (!this.ibmCloudApiKey) {
- throw new Error("Missing IBM Cloud API Key");
- }
-
- if (!this.projectId) {
- throw new Error("Missing WatsonX AI Project ID");
- }
- }
-
- _llmType() {
- return "watsonx_ai";
- }
-
- /**
- * Calls the WatsonX AI endpoint and retrieves the result.
- * @param {string} prompt The input prompt.
- * @returns {Promise} A promise that resolves to the generated string.
- */
- /** @ignore */
- async _call(
- prompt: string,
- _options: this["ParsedCallOptions"]
- ): Promise {
- interface WatsonxAIResponse {
- results: {
- generated_text: string;
- generated_token_count: number;
- input_token_count: number;
- }[];
- errors: {
- code: string;
- message: string;
- }[];
- }
- const response = (await this.caller.call(async () =>
- fetch(this.endpoint, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- Accept: "application/json",
- Authorization: `Bearer ${await this.generateToken()}`,
- },
- body: JSON.stringify({
- project_id: this.projectId,
- model_id: this.modelId,
- input: prompt,
- parameters: this.modelParameters,
- }),
- }).then((res) => res.json())
- )) as WatsonxAIResponse;
-
- /**
- * Handle Errors for invalid requests.
- */
- if (response.errors) {
- throw new Error(response.errors[0].message);
- }
-
- return response.results[0].generated_text;
- }
-
- async generateToken(): Promise {
- if (this.ibmCloudToken && this.ibmCloudTokenExpiresAt) {
- if (this.ibmCloudTokenExpiresAt > Date.now()) {
- return this.ibmCloudToken;
- }
- }
-
- interface TokenResponse {
- access_token: string;
- expiration: number;
- }
-
- const urlTokenParams = new URLSearchParams();
- urlTokenParams.append(
- "grant_type",
- "urn:ibm:params:oauth:grant-type:apikey"
- );
- urlTokenParams.append("apikey", this.ibmCloudApiKey as string);
-
- const data = (await fetch("https://iam.cloud.ibm.com/identity/token", {
- method: "POST",
- headers: {
- "Content-Type": "application/x-www-form-urlencoded",
- },
- body: urlTokenParams,
- }).then((res) => res.json())) as TokenResponse;
-
- this.ibmCloudTokenExpiresAt = data.expiration * 1000;
- this.ibmCloudToken = data.access_token;
-
- return this.ibmCloudToken;
- }
-}
+export * from "@langchain/community/llms/watsonx_ai";
diff --git a/langchain/src/llms/writer.ts b/langchain/src/llms/writer.ts
index 323167d41bdc..225f212949d8 100644
--- a/langchain/src/llms/writer.ts
+++ b/langchain/src/llms/writer.ts
@@ -1,172 +1 @@
-import { Writer as WriterClient } from "@writerai/writer-sdk";
-
-import { BaseLLMParams, LLM } from "./base.js";
-import { getEnvironmentVariable } from "../util/env.js";
-
-/**
- * Interface for the input parameters specific to the Writer model.
- */
-export interface WriterInput extends BaseLLMParams {
- /** Writer API key */
- apiKey?: string;
-
- /** Writer organization ID */
- orgId?: string | number;
-
- /** Model to use */
- model?: string;
-
- /** Sampling temperature to use */
- temperature?: number;
-
- /** Minimum number of tokens to generate. */
- minTokens?: number;
-
- /** Maximum number of tokens to generate in the completion. */
- maxTokens?: number;
-
- /** Generates this many completions server-side and returns the "best"." */
- bestOf?: number;
-
- /** Penalizes repeated tokens according to frequency. */
- frequencyPenalty?: number;
-
- /** Whether to return log probabilities. */
- logprobs?: number;
-
- /** Number of completions to generate. */
- n?: number;
-
- /** Penalizes repeated tokens regardless of frequency. */
- presencePenalty?: number;
-
- /** Total probability mass of tokens to consider at each step. */
- topP?: number;
-}
-
-/**
- * Class representing a Writer Large Language Model (LLM). It interacts
- * with the Writer API to generate text completions.
- */
-export class Writer extends LLM implements WriterInput {
- static lc_name() {
- return "Writer";
- }
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- apiKey: "WRITER_API_KEY",
- orgId: "WRITER_ORG_ID",
- };
- }
-
- get lc_aliases(): { [key: string]: string } | undefined {
- return {
- apiKey: "writer_api_key",
- orgId: "writer_org_id",
- };
- }
-
- lc_serializable = true;
-
- apiKey: string;
-
- orgId: number;
-
- model = "palmyra-instruct";
-
- temperature?: number;
-
- minTokens?: number;
-
- maxTokens?: number;
-
- bestOf?: number;
-
- frequencyPenalty?: number;
-
- logprobs?: number;
-
- n?: number;
-
- presencePenalty?: number;
-
- topP?: number;
-
- constructor(fields?: WriterInput) {
- super(fields ?? {});
-
- const apiKey = fields?.apiKey ?? getEnvironmentVariable("WRITER_API_KEY");
- const orgId = fields?.orgId ?? getEnvironmentVariable("WRITER_ORG_ID");
-
- if (!apiKey) {
- throw new Error(
- "Please set the WRITER_API_KEY environment variable or pass it to the constructor as the apiKey field."
- );
- }
-
- if (!orgId) {
- throw new Error(
- "Please set the WRITER_ORG_ID environment variable or pass it to the constructor as the orgId field."
- );
- }
-
- this.apiKey = apiKey;
- this.orgId = typeof orgId === "string" ? parseInt(orgId, 10) : orgId;
- this.model = fields?.model ?? this.model;
- this.temperature = fields?.temperature ?? this.temperature;
- this.minTokens = fields?.minTokens ?? this.minTokens;
- this.maxTokens = fields?.maxTokens ?? this.maxTokens;
- this.bestOf = fields?.bestOf ?? this.bestOf;
- this.frequencyPenalty = fields?.frequencyPenalty ?? this.frequencyPenalty;
- this.logprobs = fields?.logprobs ?? this.logprobs;
- this.n = fields?.n ?? this.n;
- this.presencePenalty = fields?.presencePenalty ?? this.presencePenalty;
- this.topP = fields?.topP ?? this.topP;
- }
-
- _llmType() {
- return "writer";
- }
-
- /** @ignore */
- async _call(
- prompt: string,
- options: this["ParsedCallOptions"]
- ): Promise {
- const sdk = new WriterClient({
- security: {
- apiKey: this.apiKey,
- },
- organizationId: this.orgId,
- });
-
- return this.caller.callWithOptions({ signal: options.signal }, async () => {
- try {
- const res = await sdk.completions.create({
- completionRequest: {
- prompt,
- stop: options.stop,
- temperature: this.temperature,
- minTokens: this.minTokens,
- maxTokens: this.maxTokens,
- bestOf: this.bestOf,
- n: this.n,
- frequencyPenalty: this.frequencyPenalty,
- logprobs: this.logprobs,
- presencePenalty: this.presencePenalty,
- topP: this.topP,
- },
- modelId: this.model,
- });
- return (
- res.completionResponse?.choices?.[0].text ?? "No completion found."
- );
- } catch (e) {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- (e as any).response = (e as any).rawResponse;
- throw e;
- }
- });
- }
-}
+export * from "@langchain/community/llms/writer";
diff --git a/langchain/src/llms/yandex.ts b/langchain/src/llms/yandex.ts
index 96b70e7ced55..d19f0acf6b0c 100644
--- a/langchain/src/llms/yandex.ts
+++ b/langchain/src/llms/yandex.ts
@@ -1,123 +1 @@
-import { getEnvironmentVariable } from "../util/env.js";
-import { LLM, BaseLLMParams } from "./base.js";
-
-const apiUrl = "https://llm.api.cloud.yandex.net/llm/v1alpha/instruct";
-
-export interface YandexGPTInputs extends BaseLLMParams {
- /**
- * What sampling temperature to use.
- * Should be a double number between 0 (inclusive) and 1 (inclusive).
- */
- temperature?: number;
-
- /**
- * Maximum limit on the total number of tokens
- * used for both the input prompt and the generated response.
- */
- maxTokens?: number;
-
- /** Model name to use. */
- model?: string;
-
- /**
- * Yandex Cloud Api Key for service account
- * with the `ai.languageModels.user` role.
- */
- apiKey?: string;
-
- /**
- * Yandex Cloud IAM token for service account
- * with the `ai.languageModels.user` role.
- */
- iamToken?: string;
-}
-
-export class YandexGPT extends LLM implements YandexGPTInputs {
- static lc_name() {
- return "Yandex GPT";
- }
-
- get lc_secrets(): { [key: string]: string } | undefined {
- return {
- apiKey: "YC_API_KEY",
- iamToken: "YC_IAM_TOKEN",
- };
- }
-
- temperature = 0.6;
-
- maxTokens = 1700;
-
- model = "general";
-
- apiKey?: string;
-
- iamToken?: string;
-
- constructor(fields?: YandexGPTInputs) {
- super(fields ?? {});
-
- const apiKey = fields?.apiKey ?? getEnvironmentVariable("YC_API_KEY");
-
- const iamToken = fields?.iamToken ?? getEnvironmentVariable("YC_IAM_TOKEN");
-
- if (apiKey === undefined && iamToken === undefined) {
- throw new Error(
- "Please set the YC_API_KEY or YC_IAM_TOKEN environment variable or pass it to the constructor as the apiKey or iamToken field."
- );
- }
-
- this.apiKey = apiKey;
- this.iamToken = iamToken;
- this.maxTokens = fields?.maxTokens ?? this.maxTokens;
- this.temperature = fields?.temperature ?? this.temperature;
- this.model = fields?.model ?? this.model;
- }
-
- _llmType() {
- return "yandexgpt";
- }
-
- /** @ignore */
- async _call(
- prompt: string,
- options: this["ParsedCallOptions"]
- ): Promise {
- // Hit the `generate` endpoint on the `large` model
- return this.caller.callWithOptions({ signal: options.signal }, async () => {
- const headers = { "Content-Type": "application/json", Authorization: "" };
- if (this.apiKey !== undefined) {
- headers.Authorization = `Api-Key ${this.apiKey}`;
- } else {
- headers.Authorization = `Bearer ${this.iamToken}`;
- }
- const bodyData = {
- model: this.model,
- generationOptions: {
- temperature: this.temperature,
- maxTokens: this.maxTokens,
- },
-
- requestText: prompt,
- };
-
- try {
- const response = await fetch(apiUrl, {
- method: "POST",
- headers,
- body: JSON.stringify(bodyData),
- });
- if (!response.ok) {
- throw new Error(
- `Failed to fetch ${apiUrl} from YandexGPT: ${response.status}`
- );
- }
-
- const responseData = await response.json();
- return responseData.result.alternatives[0].text;
- } catch (error) {
- throw new Error(`Failed to fetch ${apiUrl} from YandexGPT ${error}`);
- }
- });
- }
-}
+export * from "@langchain/community/llms/yandex";
diff --git a/langchain/src/load/import_type.d.ts b/langchain/src/load/import_type.d.ts
index 9b2b3abbde95..5add518536fb 100644
--- a/langchain/src/load/import_type.d.ts
+++ b/langchain/src/load/import_type.d.ts
@@ -522,59 +522,9 @@ export interface OptionalImportMap {
export interface SecretMap {
ANTHROPIC_API_KEY?: string;
AWS_ACCESS_KEY_ID?: string;
- AWS_SECRETE_ACCESS_KEY?: string;
AWS_SECRET_ACCESS_KEY?: string;
- AWS_SESSION_TOKEN?: string;
- AZURE_OPENAI_API_KEY?: string;
- BAIDU_API_KEY?: string;
- BAIDU_SECRET_KEY?: string;
- BEDROCK_AWS_ACCESS_KEY_ID?: string;
- BEDROCK_AWS_SECRET_ACCESS_KEY?: string;
- CLOUDFLARE_API_TOKEN?: string;
- COHERE_API_KEY?: string;
- DATABERRY_API_KEY?: string;
- FIREWORKS_API_KEY?: string;
- GOOGLE_API_KEY?: string;
- GOOGLE_PALM_API_KEY?: string;
- GOOGLE_PLACES_API_KEY?: string;
- GOOGLE_VERTEX_AI_WEB_CREDENTIALS?: string;
- GRADIENT_ACCESS_TOKEN?: string;
- GRADIENT_WORKSPACE_ID?: string;
- HUGGINGFACEHUB_API_KEY?: string;
- IBM_CLOUD_API_KEY?: string;
- IFLYTEK_API_KEY?: string;
- IFLYTEK_API_SECRET?: string;
- MILVUS_PASSWORD?: string;
- MILVUS_SSL?: string;
- MILVUS_USERNAME?: string;
- MINIMAX_API_KEY?: string;
- MINIMAX_GROUP_ID?: string;
OPENAI_API_KEY?: string;
- OPENAI_ORGANIZATION?: string;
- PLANETSCALE_DATABASE_URL?: string;
- PLANETSCALE_HOST?: string;
- PLANETSCALE_PASSWORD?: string;
- PLANETSCALE_USERNAME?: string;
PROMPTLAYER_API_KEY?: string;
- QDRANT_API_KEY?: string;
- QDRANT_URL?: string;
- REDIS_PASSWORD?: string;
- REDIS_URL?: string;
- REDIS_USERNAME?: string;
REMOTE_RETRIEVER_AUTH_BEARER?: string;
- REPLICATE_API_TOKEN?: string;
- SEARXNG_API_BASE?: string;
- UPSTASH_REDIS_REST_TOKEN?: string;
- UPSTASH_REDIS_REST_URL?: string;
- VECTARA_API_KEY?: string;
- VECTARA_CORPUS_ID?: string;
- VECTARA_CUSTOMER_ID?: string;
- WATSONX_PROJECT_ID?: string;
- WRITER_API_KEY?: string;
- WRITER_ORG_ID?: string;
- YC_API_KEY?: string;
- YC_IAM_TOKEN?: string;
ZAPIER_NLA_API_KEY?: string;
- ZEP_API_KEY?: string;
- ZEP_API_URL?: string;
}
diff --git a/langchain/src/load/index.ts b/langchain/src/load/index.ts
index 0f4fe863a1e7..c0522c9bd151 100644
--- a/langchain/src/load/index.ts
+++ b/langchain/src/load/index.ts
@@ -7,7 +7,8 @@ export async function load(
text: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
secretsMap: Record = {},
- optionalImportsMap: OptionalImportMap = {}
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ optionalImportsMap: OptionalImportMap & Record = {}
): Promise {
return coreLoad(text, {
secretsMap,
diff --git a/langchain/src/retrievers/amazon_kendra.ts b/langchain/src/retrievers/amazon_kendra.ts
index fb2ba2123b4f..8a734c4eea6f 100644
--- a/langchain/src/retrievers/amazon_kendra.ts
+++ b/langchain/src/retrievers/amazon_kendra.ts
@@ -1,317 +1 @@
-import {
- AttributeFilter,
- DocumentAttribute,
- DocumentAttributeValue,
- KendraClient,
- KendraClientConfig,
- QueryCommand,
- QueryCommandOutput,
- QueryResultItem,
- RetrieveCommand,
- RetrieveCommandOutput,
- RetrieveResultItem,
-} from "@aws-sdk/client-kendra";
-
-import { BaseRetriever } from "../schema/retriever.js";
-import { Document } from "../document.js";
-
-/**
- * Interface for the arguments required to initialize an
- * AmazonKendraRetriever instance.
- */
-export interface AmazonKendraRetrieverArgs {
- indexId: string;
- topK: number;
- region: string;
- attributeFilter?: AttributeFilter;
- clientOptions?: KendraClientConfig;
-}
-
-/**
- * Class for interacting with Amazon Kendra, an intelligent search service
- * provided by AWS. Extends the BaseRetriever class.
- * @example
- * ```typescript
- * const retriever = new AmazonKendraRetriever({
- * topK: 10,
- * indexId: "YOUR_INDEX_ID",
- * region: "us-east-2",
- * clientOptions: {
- * credentials: {
- * accessKeyId: "YOUR_ACCESS_KEY_ID",
- * secretAccessKey: "YOUR_SECRET_ACCESS_KEY",
- * },
- * },
- * });
- *
- * const docs = await retriever.getRelevantDocuments("How are clouds formed?");
- * ```
- */
-export class AmazonKendraRetriever extends BaseRetriever {
- static lc_name() {
- return "AmazonKendraRetriever";
- }
-
- lc_namespace = ["langchain", "retrievers", "amazon_kendra"];
-
- indexId: string;
-
- topK: number;
-
- kendraClient: KendraClient;
-
- attributeFilter?: AttributeFilter;
-
- constructor({
- indexId,
- topK = 10,
- clientOptions,
- attributeFilter,
- region,
- }: AmazonKendraRetrieverArgs) {
- super();
-
- if (!region) {
- throw new Error("Please pass regionName field to the constructor!");
- }
-
- if (!indexId) {
- throw new Error("Please pass Kendra Index Id to the constructor");
- }
-
- this.topK = topK;
- this.kendraClient = new KendraClient({
- region,
- ...clientOptions,
- });
- this.attributeFilter = attributeFilter;
- this.indexId = indexId;
- }
-
- // A method to combine title and excerpt into a single string.
- /**
- * Combines title and excerpt into a single string.
- * @param title The title of the document.
- * @param excerpt An excerpt from the document.
- * @returns A single string combining the title and excerpt.
- */
- combineText(title?: string, excerpt?: string): string {
- let text = "";
- if (title) {
- text += `Document Title: ${title}\n`;
- }
- if (excerpt) {
- text += `Document Excerpt: \n${excerpt}\n`;
- }
- return text;
- }
-
- // A method to clean the result text by replacing sequences of whitespace with a single space and removing ellipses.
- /**
- * Cleans the result text by replacing sequences of whitespace with a
- * single space and removing ellipses.
- * @param resText The result text to clean.
- * @returns The cleaned result text.
- */
- cleanResult(resText: string) {
- const res = resText.replace(/\s+/g, " ").replace(/\.\.\./g, "");
- return res;
- }
-
- // A method to extract the attribute value from a DocumentAttributeValue object.
- /**
- * Extracts the attribute value from a DocumentAttributeValue object.
- * @param value The DocumentAttributeValue object to extract the value from.
- * @returns The extracted attribute value.
- */
- getDocAttributeValue(value: DocumentAttributeValue) {
- if (value.DateValue) {
- return value.DateValue;
- }
- if (value.LongValue) {
- return value.LongValue;
- }
- if (value.StringListValue) {
- return value.StringListValue;
- }
- if (value.StringValue) {
- return value.StringValue;
- }
- return "";
- }
-
- // A method to extract the attribute key-value pairs from an array of DocumentAttribute objects.
- /**
- * Extracts the attribute key-value pairs from an array of
- * DocumentAttribute objects.
- * @param documentAttributes The array of DocumentAttribute objects to extract the key-value pairs from.
- * @returns An object containing the extracted attribute key-value pairs.
- */
- getDocAttributes(documentAttributes?: DocumentAttribute[]): {
- [key: string]: unknown;
- } {
- const attributes: { [key: string]: unknown } = {};
- if (documentAttributes) {
- for (const attr of documentAttributes) {
- if (attr.Key && attr.Value) {
- attributes[attr.Key] = this.getDocAttributeValue(attr.Value);
- }
- }
- }
- return attributes;
- }
-
- // A method to convert a RetrieveResultItem object into a Document object.
- /**
- * Converts a RetrieveResultItem object into a Document object.
- * @param item The RetrieveResultItem object to convert.
- * @returns A Document object.
- */
- convertRetrieverItem(item: RetrieveResultItem) {
- const title = item.DocumentTitle || "";
- const excerpt = item.Content ? this.cleanResult(item.Content) : "";
- const pageContent = this.combineText(title, excerpt);
- const source = item.DocumentURI;
- const attributes = this.getDocAttributes(item.DocumentAttributes);
- const metadata = {
- source,
- title,
- excerpt,
- document_attributes: attributes,
- };
-
- return new Document({ pageContent, metadata });
- }
-
- // A method to extract the top-k documents from a RetrieveCommandOutput object.
- /**
- * Extracts the top-k documents from a RetrieveCommandOutput object.
- * @param response The RetrieveCommandOutput object to extract the documents from.
- * @param pageSize The number of documents to extract.
- * @returns An array of Document objects.
- */
- getRetrieverDocs(
- response: RetrieveCommandOutput,
- pageSize: number
- ): Document[] {
- if (!response.ResultItems) return [];
- const { length } = response.ResultItems;
- const count = length < pageSize ? length : pageSize;
-
- return response.ResultItems.slice(0, count).map((item) =>
- this.convertRetrieverItem(item)
- );
- }
-
- // A method to extract the excerpt text from a QueryResultItem object.
- /**
- * Extracts the excerpt text from a QueryResultItem object.
- * @param item The QueryResultItem object to extract the excerpt text from.
- * @returns The extracted excerpt text.
- */
- getQueryItemExcerpt(item: QueryResultItem) {
- if (
- item.AdditionalAttributes &&
- item.AdditionalAttributes.length &&
- item.AdditionalAttributes[0].Key === "AnswerText"
- ) {
- if (!item.AdditionalAttributes) {
- return "";
- }
- if (!item.AdditionalAttributes[0]) {
- return "";
- }
-
- return this.cleanResult(
- item.AdditionalAttributes[0].Value?.TextWithHighlightsValue?.Text || ""
- );
- } else if (item.DocumentExcerpt) {
- return this.cleanResult(item.DocumentExcerpt.Text || "");
- } else {
- return "";
- }
- }
-
- // A method to convert a QueryResultItem object into a Document object.
- /**
- * Converts a QueryResultItem object into a Document object.
- * @param item The QueryResultItem object to convert.
- * @returns A Document object.
- */
- convertQueryItem(item: QueryResultItem) {
- const title = item.DocumentTitle?.Text || "";
- const excerpt = this.getQueryItemExcerpt(item);
- const pageContent = this.combineText(title, excerpt);
- const source = item.DocumentURI;
- const attributes = this.getDocAttributes(item.DocumentAttributes);
- const metadata = {
- source,
- title,
- excerpt,
- document_attributes: attributes,
- };
-
- return new Document({ pageContent, metadata });
- }
-
- // A method to extract the top-k documents from a QueryCommandOutput object.
- /**
- * Extracts the top-k documents from a QueryCommandOutput object.
- * @param response The QueryCommandOutput object to extract the documents from.
- * @param pageSize The number of documents to extract.
- * @returns An array of Document objects.
- */
- getQueryDocs(response: QueryCommandOutput, pageSize: number) {
- if (!response.ResultItems) return [];
- const { length } = response.ResultItems;
- const count = length < pageSize ? length : pageSize;
- return response.ResultItems.slice(0, count).map((item) =>
- this.convertQueryItem(item)
- );
- }
-
- // A method to send a retrieve or query request to Kendra and return the top-k documents.
- /**
- * Sends a retrieve or query request to Kendra and returns the top-k
- * documents.
- * @param query The query to send to Kendra.
- * @param topK The number of top documents to return.
- * @param attributeFilter Optional filter to apply when retrieving documents.
- * @returns A Promise that resolves to an array of Document objects.
- */
- async queryKendra(
- query: string,
- topK: number,
- attributeFilter?: AttributeFilter
- ) {
- const retrieveCommand = new RetrieveCommand({
- IndexId: this.indexId,
- QueryText: query,
- PageSize: topK,
- AttributeFilter: attributeFilter,
- });
-
- const retrieveResponse = await this.kendraClient.send(retrieveCommand);
- const retriveLength = retrieveResponse.ResultItems?.length;
-
- if (retriveLength === 0) {
- // Retrieve API returned 0 results, call query API
- const queryCommand = new QueryCommand({
- IndexId: this.indexId,
- QueryText: query,
- PageSize: topK,
- AttributeFilter: attributeFilter,
- });
-
- const queryResponse = await this.kendraClient.send(queryCommand);
- return this.getQueryDocs(queryResponse, this.topK);
- } else {
- return this.getRetrieverDocs(retrieveResponse, this.topK);
- }
- }
-
- async _getRelevantDocuments(query: string): Promise {
- const docs = await this.queryKendra(query, this.topK, this.attributeFilter);
- return docs;
- }
-}
+export * from "@langchain/community/retrievers/amazon_kendra";
diff --git a/langchain/src/retrievers/chaindesk.ts b/langchain/src/retrievers/chaindesk.ts
index 26175ede4b98..f61fccbf7e10 100644
--- a/langchain/src/retrievers/chaindesk.ts
+++ b/langchain/src/retrievers/chaindesk.ts
@@ -1,97 +1 @@
-import { BaseRetriever, type BaseRetrieverInput } from "../schema/retriever.js";
-import { Document } from "../document.js";
-import { AsyncCaller, type AsyncCallerParams } from "../util/async_caller.js";
-
-export interface ChaindeskRetrieverArgs
- extends AsyncCallerParams,
- BaseRetrieverInput {
- datastoreId: string;
- topK?: number;
- filter?: Record;
- apiKey?: string;
-}
-
-interface Berry {
- text: string;
- score: number;
- source?: string;
- [key: string]: unknown;
-}
-
-/**
- * @example
- * ```typescript
- * const retriever = new ChaindeskRetriever({
- * datastoreId: "DATASTORE_ID",
- * apiKey: "CHAINDESK_API_KEY",
- * topK: 8,
- * });
- * const docs = await retriever.getRelevantDocuments("hello");
- * ```
- */
-export class ChaindeskRetriever extends BaseRetriever {
- static lc_name() {
- return "ChaindeskRetriever";
- }
-
- lc_namespace = ["langchain", "retrievers", "chaindesk"];
-
- caller: AsyncCaller;
-
- datastoreId: string;
-
- topK?: number;
-
- filter?: Record;
-
- apiKey?: string;
-
- constructor({
- datastoreId,
- apiKey,
- topK,
- filter,
- ...rest
- }: ChaindeskRetrieverArgs) {
- super();
-
- this.caller = new AsyncCaller(rest);
- this.datastoreId = datastoreId;
- this.apiKey = apiKey;
- this.topK = topK;
- this.filter = filter;
- }
-
- async getRelevantDocuments(query: string): Promise {
- const r = await this.caller.call(
- fetch,
- `https://app.chaindesk.ai/api/datastores/${this.datastoreId}/query`,
- {
- method: "POST",
- body: JSON.stringify({
- query,
- ...(this.topK ? { topK: this.topK } : {}),
- ...(this.filter ? { filters: this.filter } : {}),
- }),
- headers: {
- "Content-Type": "application/json",
- ...(this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}),
- },
- }
- );
-
- const { results } = (await r.json()) as { results: Berry[] };
-
- return results.map(
- ({ text, score, source, ...rest }) =>
- new Document({
- pageContent: text,
- metadata: {
- score,
- source,
- ...rest,
- },
- })
- );
- }
-}
+export * from "@langchain/community/retrievers/chaindesk";
diff --git a/langchain/src/retrievers/databerry.ts b/langchain/src/retrievers/databerry.ts
index 3a8358d5b82a..39eb9679c95e 100644
--- a/langchain/src/retrievers/databerry.ts
+++ b/langchain/src/retrievers/databerry.ts
@@ -1,94 +1 @@
-import { BaseRetriever, BaseRetrieverInput } from "../schema/retriever.js";
-import { Document } from "../document.js";
-import { AsyncCaller, AsyncCallerParams } from "../util/async_caller.js";
-
-/**
- * Interface for the arguments required to create a new instance of
- * DataberryRetriever.
- */
-export interface DataberryRetrieverArgs
- extends AsyncCallerParams,
- BaseRetrieverInput {
- datastoreUrl: string;
- topK?: number;
- apiKey?: string;
-}
-
-/**
- * Interface for the structure of a Berry object returned by the Databerry
- * API.
- */
-interface Berry {
- text: string;
- score: number;
- source?: string;
- [key: string]: unknown;
-}
-
-/**
- * A specific implementation of a document retriever for the Databerry
- * API. It extends the BaseRetriever class, which is an abstract base
- * class for a document retrieval system in LangChain.
- */
-/** @deprecated Use "langchain/retrievers/chaindesk" instead */
-export class DataberryRetriever extends BaseRetriever {
- static lc_name() {
- return "DataberryRetriever";
- }
-
- lc_namespace = ["langchain", "retrievers", "databerry"];
-
- get lc_secrets() {
- return { apiKey: "DATABERRY_API_KEY" };
- }
-
- get lc_aliases() {
- return { apiKey: "api_key" };
- }
-
- caller: AsyncCaller;
-
- datastoreUrl: string;
-
- topK?: number;
-
- apiKey?: string;
-
- constructor(fields: DataberryRetrieverArgs) {
- super(fields);
- const { datastoreUrl, apiKey, topK, ...rest } = fields;
-
- this.caller = new AsyncCaller(rest);
- this.datastoreUrl = datastoreUrl;
- this.apiKey = apiKey;
- this.topK = topK;
- }
-
- async _getRelevantDocuments(query: string): Promise {
- const r = await this.caller.call(fetch, this.datastoreUrl, {
- method: "POST",
- body: JSON.stringify({
- query,
- ...(this.topK ? { topK: this.topK } : {}),
- }),
- headers: {
- "Content-Type": "application/json",
- ...(this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}),
- },
- });
-
- const { results } = (await r.json()) as { results: Berry[] };
-
- return results.map(
- ({ text, score, source, ...rest }) =>
- new Document({
- pageContent: text,
- metadata: {
- score,
- source,
- ...rest,
- },
- })
- );
- }
-}
+export * from "@langchain/community/retrievers/databerry";
diff --git a/langchain/src/retrievers/metal.ts b/langchain/src/retrievers/metal.ts
index 2632e03826eb..ea8dbb1f03e0 100644
--- a/langchain/src/retrievers/metal.ts
+++ b/langchain/src/retrievers/metal.ts
@@ -1,70 +1 @@
-import Metal from "@getmetal/metal-sdk";
-
-import { BaseRetriever, BaseRetrieverInput } from "../schema/retriever.js";
-import { Document } from "../document.js";
-
-/**
- * Interface for the fields required during the initialization of a
- * `MetalRetriever` instance. It extends the `BaseRetrieverInput`
- * interface and adds a `client` field of type `Metal`.
- */
-export interface MetalRetrieverFields extends BaseRetrieverInput {
- client: Metal;
-}
-
-/**
- * Interface to represent a response item from the Metal service. It
- * contains a `text` field and an index signature to allow for additional
- * unknown properties.
- */
-interface ResponseItem {
- text: string;
- [key: string]: unknown;
-}
-
-/**
- * Class used to interact with the Metal service, a managed retrieval &
- * memory platform. It allows you to index your data into Metal and run
- * semantic search and retrieval on it. It extends the `BaseRetriever`
- * class and requires a `Metal` instance and a dictionary of parameters to
- * pass to the Metal API during its initialization.
- * @example
- * ```typescript
- * const retriever = new MetalRetriever({
- * client: new Metal(
- * process.env.METAL_API_KEY,
- * process.env.METAL_CLIENT_ID,
- * process.env.METAL_INDEX_ID,
- * ),
- * });
- * const docs = await retriever.getRelevantDocuments("hello");
- * ```
- */
-export class MetalRetriever extends BaseRetriever {
- static lc_name() {
- return "MetalRetriever";
- }
-
- lc_namespace = ["langchain", "retrievers", "metal"];
-
- private client: Metal;
-
- constructor(fields: MetalRetrieverFields) {
- super(fields);
-
- this.client = fields.client;
- }
-
- async _getRelevantDocuments(query: string): Promise {
- const res = await this.client.search({ text: query });
-
- const items = ("data" in res ? res.data : res) as ResponseItem[];
- return items.map(
- ({ text, metadata }) =>
- new Document({
- pageContent: text,
- metadata: metadata as Record,
- })
- );
- }
-}
+export * from "@langchain/community/retrievers/metal";
diff --git a/langchain/src/retrievers/supabase.ts b/langchain/src/retrievers/supabase.ts
index ec906c42a8d7..bd3ea5d07c7c 100644
--- a/langchain/src/retrievers/supabase.ts
+++ b/langchain/src/retrievers/supabase.ts
@@ -1,238 +1 @@
-import type { SupabaseClient } from "@supabase/supabase-js";
-import { Embeddings } from "../embeddings/base.js";
-import { Document } from "../document.js";
-import { BaseRetriever, BaseRetrieverInput } from "../schema/retriever.js";
-import {
- CallbackManagerForRetrieverRun,
- Callbacks,
-} from "../callbacks/manager.js";
-
-interface SearchEmbeddingsParams {
- query_embedding: number[];
- match_count: number; // int
- filter?: Record; // jsonb
-}
-
-interface SearchKeywordParams {
- query_text: string;
- match_count: number; // int
-}
-
-interface SearchResponseRow {
- id: number;
- content: string;
- metadata: object;
- similarity: number;
-}
-
-type SearchResult = [Document, number, number];
-
-export interface SupabaseLibArgs extends BaseRetrieverInput {
- client: SupabaseClient;
- /**
- * The table name on Supabase. Defaults to "documents".
- */
- tableName?: string;
- /**
- * The name of the Similarity search function on Supabase. Defaults to "match_documents".
- */
- similarityQueryName?: string;
- /**
- * The name of the Keyword search function on Supabase. Defaults to "kw_match_documents".
- */
- keywordQueryName?: string;
- /**
- * The number of documents to return from the similarity search. Defaults to 2.
- */
- similarityK?: number;
- /**
- * The number of documents to return from the keyword search. Defaults to 2.
- */
- keywordK?: number;
-}
-
-export interface SupabaseHybridSearchParams {
- query: string;
- similarityK: number;
- keywordK: number;
-}
-
-/**
- * Class for performing hybrid search operations on a Supabase database.
- * It extends the `BaseRetriever` class and implements methods for
- * similarity search, keyword search, and hybrid search.
- */
-export class SupabaseHybridSearch extends BaseRetriever {
- static lc_name() {
- return "SupabaseHybridSearch";
- }
-
- lc_namespace = ["langchain", "retrievers", "supabase"];
-
- similarityK: number;
-
- query: string;
-
- keywordK: number;
-
- similarityQueryName: string;
-
- client: SupabaseClient;
-
- tableName: string;
-
- keywordQueryName: string;
-
- embeddings: Embeddings;
-
- constructor(embeddings: Embeddings, args: SupabaseLibArgs) {
- super(args);
- this.embeddings = embeddings;
- this.client = args.client;
- this.tableName = args.tableName || "documents";
- this.similarityQueryName = args.similarityQueryName || "match_documents";
- this.keywordQueryName = args.keywordQueryName || "kw_match_documents";
- this.similarityK = args.similarityK || 2;
- this.keywordK = args.keywordK || 2;
- }
-
- /**
- * Performs a similarity search on the Supabase database using the
- * provided query and returns the top 'k' similar documents.
- * @param query The query to use for the similarity search.
- * @param k The number of top similar documents to return.
- * @param _callbacks Optional callbacks to pass to the embedQuery method.
- * @returns A promise that resolves to an array of search results. Each result is a tuple containing a Document, its similarity score, and its ID.
- */
- protected async similaritySearch(
- query: string,
- k: number,
- _callbacks?: Callbacks // implement passing to embedQuery later
- ): Promise {
- const embeddedQuery = await this.embeddings.embedQuery(query);
-
- const matchDocumentsParams: SearchEmbeddingsParams = {
- query_embedding: embeddedQuery,
- match_count: k,
- };
-
- if (Object.keys(this.metadata ?? {}).length > 0) {
- matchDocumentsParams.filter = this.metadata;
- }
-
- const { data: searches, error } = await this.client.rpc(
- this.similarityQueryName,
- matchDocumentsParams
- );
-
- if (error) {
- throw new Error(
- `Error searching for documents: ${error.code} ${error.message} ${error.details}`
- );
- }
-
- return (searches as SearchResponseRow[]).map((resp) => [
- new Document({
- metadata: resp.metadata,
- pageContent: resp.content,
- }),
- resp.similarity,
- resp.id,
- ]);
- }
-
- /**
- * Performs a keyword search on the Supabase database using the provided
- * query and returns the top 'k' documents that match the keywords.
- * @param query The query to use for the keyword search.
- * @param k The number of top documents to return that match the keywords.
- * @returns A promise that resolves to an array of search results. Each result is a tuple containing a Document, its similarity score multiplied by 10, and its ID.
- */
- protected async keywordSearch(
- query: string,
- k: number
- ): Promise {
- const kwMatchDocumentsParams: SearchKeywordParams = {
- query_text: query,
- match_count: k,
- };
-
- const { data: searches, error } = await this.client.rpc(
- this.keywordQueryName,
- kwMatchDocumentsParams
- );
-
- if (error) {
- throw new Error(
- `Error searching for documents: ${error.code} ${error.message} ${error.details}`
- );
- }
-
- return (searches as SearchResponseRow[]).map((resp) => [
- new Document({
- metadata: resp.metadata,
- pageContent: resp.content,
- }),
- resp.similarity * 10,
- resp.id,
- ]);
- }
-
- /**
- * Combines the results of the `similaritySearch` and `keywordSearch`
- * methods and returns the top 'k' documents based on a combination of
- * similarity and keyword matching.
- * @param query The query to use for the hybrid search.
- * @param similarityK The number of top similar documents to return.
- * @param keywordK The number of top documents to return that match the keywords.
- * @param callbacks Optional callbacks to pass to the similaritySearch method.
- * @returns A promise that resolves to an array of search results. Each result is a tuple containing a Document, its combined score, and its ID.
- */
- protected async hybridSearch(
- query: string,
- similarityK: number,
- keywordK: number,
- callbacks?: Callbacks
- ): Promise {
- const similarity_search = this.similaritySearch(
- query,
- similarityK,
- callbacks
- );
-
- const keyword_search = this.keywordSearch(query, keywordK);
-
- return Promise.all([similarity_search, keyword_search])
- .then((results) => results.flat())
- .then((results) => {
- const picks = new Map();
-
- results.forEach((result) => {
- const id = result[2];
- const nextScore = result[1];
- const prevScore = picks.get(id)?.[1];
-
- if (prevScore === undefined || nextScore > prevScore) {
- picks.set(id, result);
- }
- });
-
- return Array.from(picks.values());
- })
- .then((results) => results.sort((a, b) => b[1] - a[1]));
- }
-
- async _getRelevantDocuments(
- query: string,
- runManager?: CallbackManagerForRetrieverRun
- ): Promise {
- const searchResults = await this.hybridSearch(
- query,
- this.similarityK,
- this.keywordK,
- runManager?.getChild("hybrid_search")
- );
-
- return searchResults.map(([doc]) => doc);
- }
-}
+export * from "@langchain/community/retrievers/supabase";
diff --git a/langchain/src/retrievers/tavily_search_api.ts b/langchain/src/retrievers/tavily_search_api.ts
index 7b65e36a6b89..5a59061172d6 100644
--- a/langchain/src/retrievers/tavily_search_api.ts
+++ b/langchain/src/retrievers/tavily_search_api.ts
@@ -1,140 +1 @@
-import { Document } from "../document.js";
-import { CallbackManagerForRetrieverRun } from "../callbacks/manager.js";
-import { BaseRetriever, type BaseRetrieverInput } from "../schema/retriever.js";
-import { getEnvironmentVariable } from "../util/env.js";
-
-/**
- * Options for the HydeRetriever class, which includes a BaseLanguageModel
- * instance, a VectorStore instance, and an optional promptTemplate which
- * can either be a BasePromptTemplate instance or a PromptKey.
- */
-export type TavilySearchAPIRetrieverFields = BaseRetrieverInput & {
- k?: number;
- includeGeneratedAnswer?: boolean;
- includeRawContent?: boolean;
- includeImages?: boolean;
- searchDepth?: "basic" | "advanced";
- includeDomains?: string[];
- excludeDomains?: string[];
- kwargs?: Record