From 7dd7f6fd96956bb6e78c3ff3c21754779462efd3 Mon Sep 17 00:00:00 2001 From: Jacob Lee Date: Mon, 22 Jul 2024 18:21:38 -0700 Subject: [PATCH 1/4] build[patch]: Add way to escape side effects within an entrypoint (#6174) * Add way to escape side effects within an entrypoint * Fix format * Add to all old versions * Fix comment * Remove hard error --- libs/langchain-scripts/bin/build.js | 24 ++++++++++------ libs/langchain-scripts/package.json | 2 +- libs/langchain-scripts/src/build_v2.ts | 28 +++++++++++++------ .../src/check-tree-shaking.ts | 27 ++++++++++++------ 4 files changed, 56 insertions(+), 25 deletions(-) diff --git a/libs/langchain-scripts/bin/build.js b/libs/langchain-scripts/bin/build.js index 172d1fa8fc67..40b80ac0d611 100755 --- a/libs/langchain-scripts/bin/build.js +++ b/libs/langchain-scripts/bin/build.js @@ -225,16 +225,15 @@ async function listExternals( export async function checkTreeShaking(options) { const externals = await listExternals(options?.extraInternals ?? []); const entrypoints = await listEntrypoints(); - const consoleLog = console.log; - /** @type {Map} */ + const consoleInfo = console.info; const reportMap = new Map(); for (const entrypoint of entrypoints) { let sideEffects = ""; - console.log = function (...args) { + console.info = function (...args) { const line = args.length ? args.join(" ") : ""; - if (line.trim().startsWith("First side effect in")) { + if (line.includes("First side effect in")) { sideEffects += `${line}\n`; } }; @@ -245,17 +244,26 @@ export async function checkTreeShaking(options) { experimentalLogSideEffects: true, }); + let hasUnexpectedSideEffects = sideEffects.length > 0; + if (hasUnexpectedSideEffects) { + const entrypointContent = await fs.promises.readFile(`./dist/${entrypoint.replace(/^\.\//, "")}`); + // Allow escaping side effects strictly within code directly + // within an entrypoint + hasUnexpectedSideEffects = !entrypointContent + .toString() + .includes("/* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */"); + } reportMap.set(entrypoint, { log: sideEffects, - hasSideEffects: sideEffects.length > 0, + hasUnexpectedSideEffects, }); } - console.log = consoleLog; + console.info = consoleInfo; let failed = false; for (const [entrypoint, report] of reportMap) { - if (report.hasSideEffects) { + if (report.hasUnexpectedSideEffects) { failed = true; console.log("---------------------------------"); console.log(`Tree shaking failed for ${entrypoint}`); @@ -264,7 +272,7 @@ export async function checkTreeShaking(options) { } if (failed) { - process.exit(1); + throw new Error("Tree shaking checks failed."); } else { console.log("Tree shaking checks passed!"); } diff --git a/libs/langchain-scripts/package.json b/libs/langchain-scripts/package.json index efcba3c1f946..ffa7187fece6 100644 --- a/libs/langchain-scripts/package.json +++ b/libs/langchain-scripts/package.json @@ -1,6 +1,6 @@ { "name": "@langchain/scripts", - "version": "0.0.15", + "version": "0.0.18", "description": "Shared scripts for LangChain.js", "type": "module", "engines": { diff --git a/libs/langchain-scripts/src/build_v2.ts b/libs/langchain-scripts/src/build_v2.ts index e8764f6b48e5..a07ae6ec9074 100644 --- a/libs/langchain-scripts/src/build_v2.ts +++ b/libs/langchain-scripts/src/build_v2.ts @@ -441,16 +441,16 @@ async function checkTreeShaking(config: LangChainConfig) { ); const externals = listExternals(packageJson, config?.internals ?? []); const entrypoints = listEntrypoints(packageJson); - const consoleLog = console.log; - /** @type {Map} */ + const consoleInfo = console.info; + /** @type {Map} */ const reportMap = new Map(); for (const entrypoint of entrypoints) { let sideEffects = ""; - console.log = function (...args) { + console.info = function (...args) { const line = args.length ? args.join(" ") : ""; - if (line.trim().startsWith("First side effect in")) { + if (line.includes("First side effect in")) { sideEffects += `${line}\n`; } }; @@ -461,17 +461,28 @@ async function checkTreeShaking(config: LangChainConfig) { experimentalLogSideEffects: true, }); + let hasUnexpectedSideEffects = sideEffects.length > 0; + if (hasUnexpectedSideEffects) { + const entrypointContent = await fs.promises.readFile( + `./dist/${entrypoint.replace(/^\.\//, "")}` + ); + // Allow escaping side effects strictly within code directly + // within an entrypoint + hasUnexpectedSideEffects = !entrypointContent + .toString() + .includes("/* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */"); + } reportMap.set(entrypoint, { log: sideEffects, - hasSideEffects: sideEffects.length > 0, + hasUnexpectedSideEffects, }); } - console.log = consoleLog; + console.info = consoleInfo; let failed = false; for (const [entrypoint, report] of reportMap) { - if (report.hasSideEffects) { + if (report.hasUnexpectedSideEffects) { failed = true; console.log("---------------------------------"); console.log(`Tree shaking failed for ${entrypoint}`); @@ -480,7 +491,8 @@ async function checkTreeShaking(config: LangChainConfig) { } if (failed) { - process.exit(1); + // TODO: Throw a hard error here + console.log("Tree shaking checks failed."); } else { console.log("Tree shaking checks passed!"); } diff --git a/libs/langchain-scripts/src/check-tree-shaking.ts b/libs/langchain-scripts/src/check-tree-shaking.ts index d5f724607948..cabec3b60200 100644 --- a/libs/langchain-scripts/src/check-tree-shaking.ts +++ b/libs/langchain-scripts/src/check-tree-shaking.ts @@ -60,21 +60,21 @@ async function listExternals( export async function checkTreeShaking(options?: TreeShakingArgs) { const externals = await listExternals(options?.extraInternals ?? []); const entrypoints = await listEntrypoints(); - const consoleLog = console.log; + const consoleInfo = console.info; const reportMap: Map< string, { log: string; - hasSideEffects: boolean; + hasUnexpectedSideEffects: boolean; } > = new Map(); for (const entrypoint of entrypoints) { let sideEffects = ""; - console.log = function (...args) { + console.info = function (...args) { const line = args.length ? args.join(" ") : ""; - if (line.trim().startsWith("First side effect in")) { + if (line.includes("First side effect in")) { sideEffects += `${line}\n`; } }; @@ -85,17 +85,28 @@ export async function checkTreeShaking(options?: TreeShakingArgs) { experimentalLogSideEffects: true, }); + let hasUnexpectedSideEffects = sideEffects.length > 0; + if (hasUnexpectedSideEffects) { + const entrypointContent = await fs.readFile( + `./dist/${entrypoint.replace(/^\.\//, "")}` + ); + // Allow escaping side effects strictly within code directly + // within an entrypoint + hasUnexpectedSideEffects = !entrypointContent + .toString() + .includes("/* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */"); + } reportMap.set(entrypoint, { log: sideEffects, - hasSideEffects: sideEffects.length > 0, + hasUnexpectedSideEffects, }); } - console.log = consoleLog; + console.info = consoleInfo; let failed = false; for (const [entrypoint, report] of reportMap) { - if (report.hasSideEffects) { + if (report.hasUnexpectedSideEffects) { failed = true; console.log("---------------------------------"); console.log(`Tree shaking failed for ${entrypoint}`); @@ -104,7 +115,7 @@ export async function checkTreeShaking(options?: TreeShakingArgs) { } if (failed) { - process.exit(1); + throw new Error("Tree shaking checks failed."); } else { console.log("Tree shaking checks passed!"); } From 6d34d5980910a25b217caadd1084f55b0bfd09d8 Mon Sep 17 00:00:00 2001 From: Jacob Lee Date: Mon, 22 Jul 2024 18:30:58 -0700 Subject: [PATCH 2/4] Hide OllamaFunctions from sidebar (#6176) --- docs/core_docs/docs/integrations/chat/ollama_functions.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/core_docs/docs/integrations/chat/ollama_functions.mdx b/docs/core_docs/docs/integrations/chat/ollama_functions.mdx index e4b38a3f5406..8dd6ad935f22 100644 --- a/docs/core_docs/docs/integrations/chat/ollama_functions.mdx +++ b/docs/core_docs/docs/integrations/chat/ollama_functions.mdx @@ -1,5 +1,6 @@ --- sidebar_label: Ollama Functions +sidebar_class_name: hidden --- # Ollama Functions From f2b54c934e0d153bd2b5ca3ce66a10b2262edfcf Mon Sep 17 00:00:00 2001 From: Brace Sproul Date: Tue, 23 Jul 2024 10:30:50 -0700 Subject: [PATCH 3/4] docs[patch]: Use llama3 in example docs (#6180) --- .../docs/integrations/chat/ollama.mdx | 6 ++++- .../src/models/chat/integration_ollama.ts | 24 +++++++++++++------ .../chat/integration_ollama_json_mode.ts | 15 ++++++------ 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/docs/core_docs/docs/integrations/chat/ollama.mdx b/docs/core_docs/docs/integrations/chat/ollama.mdx index 1919517e956f..d7c50b190630 100644 --- a/docs/core_docs/docs/integrations/chat/ollama.mdx +++ b/docs/core_docs/docs/integrations/chat/ollama.mdx @@ -30,6 +30,10 @@ import OllamaExample from "@examples/models/chat/integration_ollama.ts"; {OllamaExample} +:::tip +See a LangSmith trace of the above example [here](https://smith.langchain.com/public/c4f3cb1a-4496-40bd-854c-898118b21809/r) +::: + ## Tools Ollama now offers support for native tool calling. The example below demonstrates how you can invoke a tool from an Ollama model. @@ -61,7 +65,7 @@ import OllamaJSONModeExample from "@examples/models/chat/integration_ollama_json {OllamaJSONModeExample} :::tip -You can see a simple LangSmith trace of this [here](https://smith.langchain.com/public/1fbd5660-b7fd-41c3-9d3a-a6ecc735277c/r) +You can see a simple LangSmith trace of this [here](https://smith.langchain.com/public/54c0430c-0d59-4121-b1ca-34ac1e95e0bb/r) ::: ## Multimodal models diff --git a/examples/src/models/chat/integration_ollama.ts b/examples/src/models/chat/integration_ollama.ts index 0015ec9d611e..460ce38981bb 100644 --- a/examples/src/models/chat/integration_ollama.ts +++ b/examples/src/models/chat/integration_ollama.ts @@ -3,7 +3,7 @@ import { StringOutputParser } from "@langchain/core/output_parsers"; const model = new ChatOllama({ baseUrl: "http://localhost:11434", // Default value - model: "llama2", // Default value + model: "llama3", }); const stream = await model @@ -18,13 +18,23 @@ for await (const chunk of stream) { console.log(chunks.join("")); /* - Thank you for your question! I'm happy to help. However, I must point out that the phrase "I love programming" is not grammatically correct in German. The word "love" does not have a direct translation in German, and it would be more appropriate to say "I enjoy programming" or "I am passionate about programming." +The translation of "I love programming" into German is: - In German, you can express your enthusiasm for something like this: +Ich liebe Programmieren. - * Ich möchte Programmieren (I want to program) - * Ich mag Programmieren (I like to program) - * Ich bin passioniert über Programmieren (I am passionate about programming) +Here's a breakdown of the translation: - I hope this helps! Let me know if you have any other questions. +* Ich = I +* liebe = love +* Programmieren = programming (note: this word is the infinitive form, which is often used in informal contexts or when speaking about one's profession or hobby) + +If you want to make it sound more formal or use the correct verb conjugation for "I", you can say: + +Ich bin ein großer Fan von Programmieren. + +This translates to: + +I am a big fan of programming. + +In this sentence, "bin" is the first person singular present tense of the verb "sein", which means "to be". The phrase "ein großer Fan" means "a big fan". */ diff --git a/examples/src/models/chat/integration_ollama_json_mode.ts b/examples/src/models/chat/integration_ollama_json_mode.ts index d782f4804431..926d99af803c 100644 --- a/examples/src/models/chat/integration_ollama_json_mode.ts +++ b/examples/src/models/chat/integration_ollama_json_mode.ts @@ -11,7 +11,7 @@ const prompt = ChatPromptTemplate.fromMessages([ const model = new ChatOllama({ baseUrl: "http://localhost:11434", // Default value - model: "llama2", // Default value + model: "llama3", format: "json", }); @@ -26,11 +26,12 @@ console.log(result); /* AIMessage { - content: '{\n' + - '"original": "I love programming",\n' + - '"translated": "Ich liebe Programmierung"\n' + - '}', - response_metadata: { ... }, - usage_metadata: { ... } + "content": "{\n\"original\": \"I love programming\",\n\"translated\": \"Ich liebe Programmieren\"\n}", + "response_metadata": { ... }, + "usage_metadata": { + "input_tokens": 47, + "output_tokens": 20, + "total_tokens": 67 + } } */ From 99a87601ae656097176b8be59ab638e3b690cf4b Mon Sep 17 00:00:00 2001 From: Sachin Chaurasiya Date: Wed, 24 Jul 2024 00:11:07 +0530 Subject: [PATCH 4/4] docs[patch]: Update PineconeStore creation to include namespace parameter (#6169) * docs: Update PineconeStore creation to include namespace parameter * yarn format --------- Co-authored-by: bracesproul --- docs/core_docs/docs/how_to/qa_per_user.ipynb | 12 +++++++++++- examples/src/indexes/vector_stores/pinecone/mmr.ts | 12 +++++++++++- .../src/indexes/vector_stores/pinecone/query_docs.ts | 12 +++++++++++- ...c_similarity_example_selector_custom_retriever.ts | 12 +++++++++++- 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/docs/core_docs/docs/how_to/qa_per_user.ipynb b/docs/core_docs/docs/how_to/qa_per_user.ipynb index b903c7797a9b..4e29ca6dd5b7 100644 --- a/docs/core_docs/docs/how_to/qa_per_user.ipynb +++ b/docs/core_docs/docs/how_to/qa_per_user.ipynb @@ -121,9 +121,19 @@ "\n", "const pineconeIndex = pinecone.Index(Deno.env.get(\"PINECONE_INDEX\"));\n", "\n", + "/**\n", + " * Pinecone allows you to partition the records in an index into namespaces. \n", + " * Queries and other operations are then limited to one namespace, \n", + " * so different requests can search different subsets of your index.\n", + " * Read more about namespaces here: https://docs.pinecone.io/guides/indexes/use-namespaces\n", + " * \n", + " * NOTE: If you have namespace enabled in your Pinecone index, you must provide the namespace when creating the PineconeStore.\n", + " */\n", + "const namespace = \"pinecone\";\n", + "\n", "const vectorStore = await PineconeStore.fromExistingIndex(\n", " new OpenAIEmbeddings(),\n", - " { pineconeIndex },\n", + " { pineconeIndex, namespace },\n", ");\n", "\n", "await vectorStore.addDocuments(\n", diff --git a/examples/src/indexes/vector_stores/pinecone/mmr.ts b/examples/src/indexes/vector_stores/pinecone/mmr.ts index 223ec3726377..10a85253b3ea 100644 --- a/examples/src/indexes/vector_stores/pinecone/mmr.ts +++ b/examples/src/indexes/vector_stores/pinecone/mmr.ts @@ -11,9 +11,19 @@ const pinecone = new Pinecone(); const pineconeIndex = pinecone.Index(process.env.PINECONE_INDEX!); +/** + * Pinecone allows you to partition the records in an index into namespaces. + * Queries and other operations are then limited to one namespace, + * so different requests can search different subsets of your index. + * Read more about namespaces here: https://docs.pinecone.io/guides/indexes/use-namespaces + * + * NOTE: If you have namespace enabled in your Pinecone index, you must provide the namespace when creating the PineconeStore. + */ +const namespace = "pinecone"; + const vectorStore = await PineconeStore.fromExistingIndex( new OpenAIEmbeddings(), - { pineconeIndex } + { pineconeIndex, namespace } ); /* Search the vector DB independently with meta filters */ diff --git a/examples/src/indexes/vector_stores/pinecone/query_docs.ts b/examples/src/indexes/vector_stores/pinecone/query_docs.ts index 72a8704d2449..6294067724ec 100644 --- a/examples/src/indexes/vector_stores/pinecone/query_docs.ts +++ b/examples/src/indexes/vector_stores/pinecone/query_docs.ts @@ -11,9 +11,19 @@ const pinecone = new Pinecone(); const pineconeIndex = pinecone.Index(process.env.PINECONE_INDEX!); +/** + * Pinecone allows you to partition the records in an index into namespaces. + * Queries and other operations are then limited to one namespace, + * so different requests can search different subsets of your index. + * Read more about namespaces here: https://docs.pinecone.io/guides/indexes/use-namespaces + * + * NOTE: If you have namespace enabled in your Pinecone index, you must provide the namespace when creating the PineconeStore. + */ +const namespace = "pinecone"; + const vectorStore = await PineconeStore.fromExistingIndex( new OpenAIEmbeddings(), - { pineconeIndex } + { pineconeIndex, namespace } ); /* Search the vector DB independently with metadata filters */ diff --git a/examples/src/prompts/semantic_similarity_example_selector_custom_retriever.ts b/examples/src/prompts/semantic_similarity_example_selector_custom_retriever.ts index 980e2cbe6557..d40f014bf131 100644 --- a/examples/src/prompts/semantic_similarity_example_selector_custom_retriever.ts +++ b/examples/src/prompts/semantic_similarity_example_selector_custom_retriever.ts @@ -11,9 +11,19 @@ const pinecone = new Pinecone(); const pineconeIndex = pinecone.Index(process.env.PINECONE_INDEX!); +/** + * Pinecone allows you to partition the records in an index into namespaces. + * Queries and other operations are then limited to one namespace, + * so different requests can search different subsets of your index. + * Read more about namespaces here: https://docs.pinecone.io/guides/indexes/use-namespaces + * + * NOTE: If you have namespace enabled in your Pinecone index, you must provide the namespace when creating the PineconeStore. + */ +const namespace = "pinecone"; + const pineconeVectorstore = await PineconeStore.fromExistingIndex( new OpenAIEmbeddings(), - { pineconeIndex } + { pineconeIndex, namespace } ); const pineconeMmrRetriever = pineconeVectorstore.asRetriever({