Skip to content

Commit

Permalink
feature: chat deployment implementation (#39)
Browse files Browse the repository at this point in the history
* Rename auth method in docs

* fix(core): Fix trim messages mutation bug (langchain-ai#7547)

* release(core): 0.3.31 (langchain-ai#7548)

* fix(community): Updated Embeddings URL (langchain-ai#7545)

* fix(community): make sure guardrailConfig can be added even with anthropic models (langchain-ai#7542)

* docs: Fix PGVectorStore import in install dependencies (TypeScript) example (langchain-ai#7533)

* fix(community): Airtable url (langchain-ai#7532)

* docs: Fix typo in OpenAIModerationChain example (langchain-ai#7528)

* docs: Resolves langchain-ai#7483, resolves langchain-ai#7274 (langchain-ai#7505)

Co-authored-by: jacoblee93 <jacoblee93@gmail.com>

* docs: Rename auth method in IBM docs (langchain-ai#7524)

* docs: correct misspelling (langchain-ai#7522)

Co-authored-by: jacoblee93 <jacoblee93@gmail.com>

* release(community): 0.3.25 (langchain-ai#7549)

* feat(azure-cosmosdb): add session context for a user mongodb (langchain-ai#7436)

Co-authored-by: jacoblee93 <jacoblee93@gmail.com>

* release(azure-cosmosdb): 0.2.7 (langchain-ai#7550)

* fix(ci): Fix build (langchain-ai#7551)

* feat(anthropic): Add Anthropic PDF support (document type) in invoke (langchain-ai#7496)

Co-authored-by: jacoblee93 <jacoblee93@gmail.com>

* release(anthropic): 0.3.12 (langchain-ai#7552)

* chore(core,langchain,community): Relax langsmith deps (langchain-ai#7556)

* release(community): 0.3.26 (langchain-ai#7557)

* release(core): 0.3.32 (langchain-ai#7558)

* Release 0.3.12 (langchain-ai#7559)

* Add deployment chat to chat class

* Upadate Watsonx sdk

* Rework interfaces in llms as well

* Bump watsonx-ai sdk version

* Remove unused code

* Add fake auth

---------

Co-authored-by: Jacob Lee <jacoblee93@gmail.com>
Co-authored-by: Jacky Chen <jackychen4@gmail.com>
Co-authored-by: Mohamed Belhadj <medbelh@gmail.com>
Co-authored-by: Brian Ploetz <bploetz@gmail.com>
Co-authored-by: Eduard-Constantin Ibinceanu <ibinceanu.eduard@yahoo.com>
Co-authored-by: Jonathan V <jonathanvelkeneers@hotmail.com>
Co-authored-by: ucev <zhangshuaiyf@icloud.com>
Co-authored-by: crisjy <cjy1994116@163.com>
Co-authored-by: Adham Badr <adhambadr2@gmail.com>
  • Loading branch information
10 people authored Jan 30, 2025
1 parent 464e56b commit 82a239e
Show file tree
Hide file tree
Showing 33 changed files with 657 additions and 179 deletions.
4 changes: 2 additions & 2 deletions docs/core_docs/docs/how_to/tool_calling_parallel.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"});\n",
"\n",
"const multiplyTool = tool(async ({ a, b }) => {\n",
" return a + b;\n",
" return a * b;\n",
"}, {\n",
" name: \"multiply\",\n",
" description: \"Multiplies a and b\",\n",
Expand Down Expand Up @@ -220,4 +220,4 @@
},
"nbformat": 4,
"nbformat_minor": 4
}
}
4 changes: 2 additions & 2 deletions docs/core_docs/docs/how_to/tool_results_pass_to_model.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
":::\n",
"```\n",
"\n",
"Some models are capable of [**tool calling**](/docs/concepts/tool_calling) - generating arguments that conform to a specific user-provided schema. This guide will demonstrate how to use those tool cals to actually call a function and properly pass the results back to the model.\n",
"Some models are capable of [**tool calling**](/docs/concepts/tool_calling) - generating arguments that conform to a specific user-provided schema. This guide will demonstrate how to use those tool calls to actually call a function and properly pass the results back to the model.\n",
"\n",
"![](../../static/img/tool_invocation.png)\n",
"\n",
Expand Down Expand Up @@ -367,4 +367,4 @@
},
"nbformat": 4,
"nbformat_minor": 4
}
}
2 changes: 1 addition & 1 deletion docs/core_docs/docs/integrations/tools/google_calendar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import IntegrationInstallTooltip from "@mdx_components/integration_install_toolt
<IntegrationInstallTooltip></IntegrationInstallTooltip>

```bash npm2yarn
npm install @langchain/openai @langchain/core
npm install @langchain/openai @langchain/core @langchain/community @langchain/langgraph
```

<CodeBlock language="typescript">{ToolExample}</CodeBlock>
Expand Down
2 changes: 1 addition & 1 deletion docs/core_docs/src/theme/VectorStoreTabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const ${vectorStoreVarName} = new MongoDBAtlasVectorSearch(embeddings, {
{
value: "PGVector",
label: "PGVector",
text: `import PGVectorStore from "@langchain/community/vectorstores/pgvector";
text: `import { PGVectorStore } from "@langchain/community/vectorstores/pgvector";
const ${vectorStoreVarName} = await PGVectorStore.initialize(embeddings, {})`,
dependencies: "@langchain/community",
Expand Down
2 changes: 1 addition & 1 deletion examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
"ioredis": "^5.3.2",
"js-yaml": "^4.1.0",
"langchain": "workspace:*",
"langsmith": "^0.2.8",
"langsmith": ">=0.2.8 <0.4.0",
"mongodb": "^6.3.0",
"pg": "^8.11.0",
"pickleparser": "^0.2.1",
Expand Down
52 changes: 52 additions & 0 deletions examples/src/models/chat/integration_anthropic_pdf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { ChatAnthropic } from "@langchain/anthropic";

import * as fs from "fs";

export const run = async () => {
const llm = new ChatAnthropic({
model: "claude-3-5-sonnet-20240620", // Only claude-3-5-sonnet-20240620 , claude-3-5-sonnet-20241022 as of Jan 2025 support PDF documents as in base64
});

// PDF needs to be in Base64.
const getLocalFile = async (path: string) => {
const localFile = await fs.readFileSync(path);
const base64File = localFile.toString("base64");
return base64File;
};

// Or remotely
const getRemoteFile = async (url: string) => {
const response = await fetch(url);
const arrayBuffer = await response.arrayBuffer();
const base64File = Buffer.from(arrayBuffer).toString("base64");
return base64File;
};

const base64 = await getRemoteFile(
"https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
);

const prompt = "Summarise the contents of this PDF";

const response = await llm.invoke([
{
role: "user",
content: [
{
type: "text",
text: prompt,
},
{
type: "document",
source: {
media_type: "application/pdf",
type: "base64",
data: base64,
},
},
],
},
]);
console.log(response.content);
return response.content;
};
21 changes: 13 additions & 8 deletions examples/src/tools/google_calendar.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { initializeAgentExecutorWithOptions } from "langchain/agents";
import { OpenAI } from "@langchain/openai";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { ChatOpenAI } from "@langchain/openai";
import { Calculator } from "@langchain/community/tools/calculator";
import {
GoogleCalendarCreateTool,
GoogleCalendarViewTool,
} from "@langchain/community/tools/google_calendar";

export async function run() {
const model = new OpenAI({
const model = new ChatOpenAI({
temperature: 0,
apiKey: process.env.OPENAI_API_KEY,
model: "gpt-4o-mini",
});

const googleCalendarParams = {
Expand All @@ -31,22 +32,26 @@ export async function run() {
new GoogleCalendarViewTool(googleCalendarParams),
];

const calendarAgent = await initializeAgentExecutorWithOptions(tools, model, {
agentType: "zero-shot-react-description",
verbose: true,
const calendarAgent = createReactAgent({
llm: model,
tools,
});

const createInput = `Create a meeting with John Doe next Friday at 4pm - adding to the agenda of it the result of 99 + 99`;

const createResult = await calendarAgent.invoke({ input: createInput });
const createResult = await calendarAgent.invoke({
messages: [{ role: "user", content: createInput }],
});
// Create Result {
// output: 'A meeting with John Doe on 29th September at 4pm has been created and the result of 99 + 99 has been added to the agenda.'
// }
console.log("Create Result", createResult);

const viewInput = `What meetings do I have this week?`;

const viewResult = await calendarAgent.invoke({ input: viewInput });
const viewResult = await calendarAgent.invoke({
messages: [{ role: "user", content: viewInput }],
});
// View Result {
// output: "You have no meetings this week between 8am and 8pm."
// }
Expand Down
4 changes: 2 additions & 2 deletions langchain-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@langchain/core",
"version": "0.3.30",
"version": "0.3.32",
"description": "Core LangChain.js abstractions and schemas",
"type": "module",
"engines": {
Expand Down Expand Up @@ -38,7 +38,7 @@
"camelcase": "6",
"decamelize": "1.2.0",
"js-tiktoken": "^1.0.12",
"langsmith": "^0.2.8",
"langsmith": ">=0.2.8 <0.4.0",
"mustache": "^4.2.0",
"p-queue": "^6.6.2",
"p-retry": "4",
Expand Down
83 changes: 82 additions & 1 deletion langchain-core/src/messages/tests/message_utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import {
mergeMessageRuns,
trimMessages,
} from "../transformers.js";
import { AIMessage } from "../ai.js";
import { AIMessage, AIMessageChunk } from "../ai.js";
import { ChatMessage } from "../chat.js";
import { HumanMessage } from "../human.js";
import { SystemMessage } from "../system.js";
import { ToolMessage } from "../tool.js";
import { BaseMessage } from "../base.js";
import {
getBufferString,
Expand Down Expand Up @@ -187,6 +188,7 @@ describe("trimMessages can trim", () => {
defaultMsgSuffixLen;
}
}
console.log(count);
return count;
};

Expand All @@ -196,6 +198,84 @@ describe("trimMessages can trim", () => {
};
};

it("should not mutate messages if no trimming occurs with strategy last", async () => {
const trimmer = trimMessages({
maxTokens: 128000,
strategy: "last",
startOn: [HumanMessage],
endOn: [AIMessage, ToolMessage],
tokenCounter: () => 1,
});
const messages = [
new HumanMessage({
content: "Fetch the last 5 emails from Flora Testington's inbox.",
additional_kwargs: {},
response_metadata: {},
}),
new AIMessageChunk({
id: "chatcmpl-abcdefg",
content: "",
additional_kwargs: {
tool_calls: [
{
function: {
name: "getEmails",
arguments: JSON.stringify({
inboxName: "flora@foo.org",
amount: 5,
folder: "Inbox",
searchString: null,
from: null,
subject: null,
}),
},
id: "foobarbaz",
index: 0,
type: "function",
},
],
},
response_metadata: {
usage: {},
},
tool_calls: [
{
name: "getEmails",
args: {
inboxName: "flora@foo.org",
amount: 5,
folder: "Inbox",
searchString: null,
from: null,
subject: null,
},
id: "foobarbaz",
type: "tool_call",
},
],
tool_call_chunks: [
{
name: "getEmails",
args: '{"inboxName":"flora@foo.org","amount":5,"folder":"Inbox","searchString":null,"from":null,"subject":null,"cc":[],"bcc":[]}',
id: "foobarbaz",
index: 0,
type: "tool_call_chunk",
},
],
invalid_tool_calls: [],
}),
new ToolMessage({
content: "a whole bunch of emails!",
name: "getEmails",
additional_kwargs: {},
response_metadata: {},
tool_call_id: "foobarbaz",
}),
];
const trimmedMessages = await trimmer.invoke(messages);
expect(trimmedMessages).toEqual(messages);
});

it("First 30 tokens, not allowing partial messages", async () => {
const { messages, dummyTokenCounter } = messagesAndTokenCounterFactory();
const trimmedMessages = await trimMessages(messages, {
Expand Down Expand Up @@ -319,6 +399,7 @@ describe("trimMessages can trim", () => {

it("Last 30 tokens, including system message, allowing partial messages, end on HumanMessage", async () => {
const { messages, dummyTokenCounter } = messagesAndTokenCounterFactory();
console.log(messages);
const trimmedMessages = await trimMessages(messages, {
maxTokens: 30,
tokenCounter: dummyTokenCounter,
Expand Down
18 changes: 11 additions & 7 deletions langchain-core/src/messages/transformers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ function _mergeMessageRuns(messages: BaseMessage[]): BaseMessage[] {
}
const merged: BaseMessage[] = [];
for (const msg of messages) {
const curr = msg; // Create a shallow copy of the message
const curr = msg;
const last = merged.pop();
if (!last) {
merged.push(curr);
Expand Down Expand Up @@ -861,20 +861,24 @@ async function _lastMaxTokens(
...rest
} = options;

// Create a copy of messages to avoid mutation
let messagesCopy = [...messages];

if (endOn) {
const endOnArr = Array.isArray(endOn) ? endOn : [endOn];
while (
messages &&
!_isMessageType(messages[messages.length - 1], endOnArr)
messagesCopy.length > 0 &&
!_isMessageType(messagesCopy[messagesCopy.length - 1], endOnArr)
) {
messages.pop();
messagesCopy = messagesCopy.slice(0, -1);
}
}

const swappedSystem = includeSystem && messages[0]._getType() === "system";
const swappedSystem =
includeSystem && messagesCopy[0]?._getType() === "system";
let reversed_ = swappedSystem
? messages.slice(0, 1).concat(messages.slice(1).reverse())
: messages.reverse();
? messagesCopy.slice(0, 1).concat(messagesCopy.slice(1).reverse())
: messagesCopy.reverse();

reversed_ = await _firstMaxTokens(reversed_, {
...rest,
Expand Down
4 changes: 2 additions & 2 deletions langchain/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "langchain",
"version": "0.3.11",
"version": "0.3.12",
"description": "Typescript bindings for langchain",
"type": "module",
"engines": {
Expand Down Expand Up @@ -530,7 +530,7 @@
"js-tiktoken": "^1.0.12",
"js-yaml": "^4.1.0",
"jsonpointer": "^5.0.1",
"langsmith": "^0.2.8",
"langsmith": ">=0.2.8 <0.4.0",
"openapi-types": "^12.1.3",
"p-retry": "4",
"uuid": "^10.0.0",
Expand Down
2 changes: 1 addition & 1 deletion langchain/src/chains/openai_moderation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface OpenAIModerationChainInput
* OpenAIModerationChainInput interface.
* @example
* ```typescript
* const moderation = new ChatOpenAIModerationChain({ throwError: true });
* const moderation = new OpenAIModerationChain({ throwError: true });
*
* const badString = "Bad naughty words from user";
*
Expand Down
2 changes: 1 addition & 1 deletion libs/langchain-anthropic/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@langchain/anthropic",
"version": "0.3.11",
"version": "0.3.12",
"description": "Anthropic integrations for LangChain.js",
"type": "module",
"engines": {
Expand Down
7 changes: 7 additions & 0 deletions libs/langchain-anthropic/src/utils/message_inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ function _formatContent(content: MessageContent) {
source,
...(cacheControl ? { cache_control: cacheControl } : {}),
};
} else if (contentPart.type === "document") {
// PDF
return {
type: "document",
source: contentPart.source,
...(cacheControl ? { cache_control: cacheControl } : {}),
};
} else if (
textTypes.find((t) => t === contentPart.type) &&
"text" in contentPart
Expand Down
2 changes: 1 addition & 1 deletion libs/langchain-azure-cosmosdb/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@langchain/azure-cosmosdb",
"version": "0.2.6",
"version": "0.2.7",
"description": "Azure CosmosDB integration for LangChain.js",
"type": "module",
"engines": {
Expand Down
Loading

0 comments on commit 82a239e

Please sign in to comment.