@langchain/openai 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/azure/chat_models.cjs +48 -0
- package/dist/azure/chat_models.d.ts +17 -0
- package/dist/azure/chat_models.js +44 -0
- package/dist/azure/llms.cjs +45 -0
- package/dist/azure/llms.d.ts +16 -0
- package/dist/azure/llms.js +41 -0
- package/dist/embeddings.cjs +2 -2
- package/dist/embeddings.js +1 -1
- package/dist/index.cjs +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/llms.cjs +3 -3
- package/dist/llms.js +1 -1
- package/dist/tests/chat_models-extended.int.test.d.ts +1 -0
- package/dist/tests/chat_models-extended.int.test.js +194 -0
- package/dist/tests/chat_models-vision.int.test.d.ts +1 -0
- package/dist/tests/chat_models-vision.int.test.js +51 -0
- package/dist/tests/chat_models.int.test.d.ts +1 -0
- package/dist/tests/chat_models.int.test.js +627 -0
- package/dist/tests/legacy.int.test.d.ts +1 -0
- package/dist/tests/legacy.int.test.js +115 -0
- package/dist/tests/llms.int.test.d.ts +1 -0
- package/dist/tests/llms.int.test.js +257 -0
- package/package.json +3 -3
- package/dist/utils/chunk.cjs +0 -11
- package/dist/utils/chunk.d.ts +0 -1
- package/dist/utils/chunk.js +0 -7
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AzureChatOpenAI = void 0;
|
|
4
|
+
const chat_models_js_1 = require("../chat_models.cjs");
|
|
5
|
+
class AzureChatOpenAI extends chat_models_js_1.ChatOpenAI {
|
|
6
|
+
_llmType() {
|
|
7
|
+
return "azure_openai";
|
|
8
|
+
}
|
|
9
|
+
get lc_aliases() {
|
|
10
|
+
return {
|
|
11
|
+
openAIApiKey: "openai_api_key",
|
|
12
|
+
openAIApiVersion: "openai_api_version",
|
|
13
|
+
openAIBasePath: "openai_api_base",
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
constructor(fields) {
|
|
17
|
+
// assume the base URL does not contain "openai" nor "deployments" prefix
|
|
18
|
+
let basePath = fields?.openAIBasePath ?? "";
|
|
19
|
+
if (!basePath.endsWith("/"))
|
|
20
|
+
basePath += "/";
|
|
21
|
+
if (!basePath.endsWith("openai/deployments"))
|
|
22
|
+
basePath += "openai/deployments";
|
|
23
|
+
const newFields = fields ? { ...fields } : fields;
|
|
24
|
+
if (newFields) {
|
|
25
|
+
newFields.azureOpenAIBasePath = basePath;
|
|
26
|
+
newFields.azureOpenAIApiDeploymentName = newFields.deploymentName;
|
|
27
|
+
newFields.azureOpenAIApiKey = newFields.openAIApiKey;
|
|
28
|
+
newFields.azureOpenAIApiVersion = newFields.openAIApiVersion;
|
|
29
|
+
}
|
|
30
|
+
super(newFields);
|
|
31
|
+
}
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
33
|
+
toJSON() {
|
|
34
|
+
const json = super.toJSON();
|
|
35
|
+
function isRecord(obj) {
|
|
36
|
+
return typeof obj === "object" && obj != null;
|
|
37
|
+
}
|
|
38
|
+
if (isRecord(json) && isRecord(json.kwargs)) {
|
|
39
|
+
delete json.kwargs.azure_openai_base_path;
|
|
40
|
+
delete json.kwargs.azure_openai_api_deployment_name;
|
|
41
|
+
delete json.kwargs.azure_openai_api_key;
|
|
42
|
+
delete json.kwargs.azure_openai_api_version;
|
|
43
|
+
delete json.kwargs.azure_open_ai_base_path;
|
|
44
|
+
}
|
|
45
|
+
return json;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.AzureChatOpenAI = AzureChatOpenAI;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ClientOptions } from "openai";
|
|
2
|
+
import { type BaseChatModelParams } from "@langchain/core/language_models/chat_models";
|
|
3
|
+
import { ChatOpenAI } from "../chat_models.js";
|
|
4
|
+
import { AzureOpenAIInput, LegacyOpenAIInput, OpenAIChatInput } from "../types.js";
|
|
5
|
+
export declare class AzureChatOpenAI extends ChatOpenAI {
|
|
6
|
+
_llmType(): string;
|
|
7
|
+
get lc_aliases(): Record<string, string>;
|
|
8
|
+
constructor(fields?: Partial<OpenAIChatInput> & Partial<AzureOpenAIInput> & {
|
|
9
|
+
openAIApiKey?: string;
|
|
10
|
+
openAIApiVersion?: string;
|
|
11
|
+
openAIBasePath?: string;
|
|
12
|
+
deploymentName?: string;
|
|
13
|
+
} & BaseChatModelParams & {
|
|
14
|
+
configuration?: ClientOptions & LegacyOpenAIInput;
|
|
15
|
+
});
|
|
16
|
+
toJSON(): any;
|
|
17
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ChatOpenAI } from "../chat_models.js";
|
|
2
|
+
export class AzureChatOpenAI extends ChatOpenAI {
|
|
3
|
+
_llmType() {
|
|
4
|
+
return "azure_openai";
|
|
5
|
+
}
|
|
6
|
+
get lc_aliases() {
|
|
7
|
+
return {
|
|
8
|
+
openAIApiKey: "openai_api_key",
|
|
9
|
+
openAIApiVersion: "openai_api_version",
|
|
10
|
+
openAIBasePath: "openai_api_base",
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
constructor(fields) {
|
|
14
|
+
// assume the base URL does not contain "openai" nor "deployments" prefix
|
|
15
|
+
let basePath = fields?.openAIBasePath ?? "";
|
|
16
|
+
if (!basePath.endsWith("/"))
|
|
17
|
+
basePath += "/";
|
|
18
|
+
if (!basePath.endsWith("openai/deployments"))
|
|
19
|
+
basePath += "openai/deployments";
|
|
20
|
+
const newFields = fields ? { ...fields } : fields;
|
|
21
|
+
if (newFields) {
|
|
22
|
+
newFields.azureOpenAIBasePath = basePath;
|
|
23
|
+
newFields.azureOpenAIApiDeploymentName = newFields.deploymentName;
|
|
24
|
+
newFields.azureOpenAIApiKey = newFields.openAIApiKey;
|
|
25
|
+
newFields.azureOpenAIApiVersion = newFields.openAIApiVersion;
|
|
26
|
+
}
|
|
27
|
+
super(newFields);
|
|
28
|
+
}
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
toJSON() {
|
|
31
|
+
const json = super.toJSON();
|
|
32
|
+
function isRecord(obj) {
|
|
33
|
+
return typeof obj === "object" && obj != null;
|
|
34
|
+
}
|
|
35
|
+
if (isRecord(json) && isRecord(json.kwargs)) {
|
|
36
|
+
delete json.kwargs.azure_openai_base_path;
|
|
37
|
+
delete json.kwargs.azure_openai_api_deployment_name;
|
|
38
|
+
delete json.kwargs.azure_openai_api_key;
|
|
39
|
+
delete json.kwargs.azure_openai_api_version;
|
|
40
|
+
delete json.kwargs.azure_open_ai_base_path;
|
|
41
|
+
}
|
|
42
|
+
return json;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AzureOpenAI = void 0;
|
|
4
|
+
const llms_js_1 = require("../llms.cjs");
|
|
5
|
+
class AzureOpenAI extends llms_js_1.OpenAI {
|
|
6
|
+
get lc_aliases() {
|
|
7
|
+
return {
|
|
8
|
+
openAIApiKey: "openai_api_key",
|
|
9
|
+
openAIApiVersion: "openai_api_version",
|
|
10
|
+
openAIBasePath: "openai_api_base",
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
constructor(fields) {
|
|
14
|
+
// assume the base URL does not contain "openai" nor "deployments" prefix
|
|
15
|
+
let basePath = fields?.openAIBasePath ?? "";
|
|
16
|
+
if (!basePath.endsWith("/"))
|
|
17
|
+
basePath += "/";
|
|
18
|
+
if (!basePath.endsWith("openai/deployments"))
|
|
19
|
+
basePath += "openai/deployments";
|
|
20
|
+
const newFields = fields ? { ...fields } : fields;
|
|
21
|
+
if (newFields) {
|
|
22
|
+
newFields.azureOpenAIBasePath = basePath;
|
|
23
|
+
newFields.azureOpenAIApiDeploymentName = newFields.deploymentName;
|
|
24
|
+
newFields.azureOpenAIApiKey = newFields.openAIApiKey;
|
|
25
|
+
newFields.azureOpenAIApiVersion = newFields.openAIApiVersion;
|
|
26
|
+
}
|
|
27
|
+
super(newFields);
|
|
28
|
+
}
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
toJSON() {
|
|
31
|
+
const json = super.toJSON();
|
|
32
|
+
function isRecord(obj) {
|
|
33
|
+
return typeof obj === "object" && obj != null;
|
|
34
|
+
}
|
|
35
|
+
if (isRecord(json) && isRecord(json.kwargs)) {
|
|
36
|
+
delete json.kwargs.azure_openai_base_path;
|
|
37
|
+
delete json.kwargs.azure_openai_api_deployment_name;
|
|
38
|
+
delete json.kwargs.azure_openai_api_key;
|
|
39
|
+
delete json.kwargs.azure_openai_api_version;
|
|
40
|
+
delete json.kwargs.azure_open_ai_base_path;
|
|
41
|
+
}
|
|
42
|
+
return json;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.AzureOpenAI = AzureOpenAI;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ClientOptions } from "openai";
|
|
2
|
+
import { type BaseLLMParams } from "@langchain/core/language_models/llms";
|
|
3
|
+
import { OpenAI } from "../llms.js";
|
|
4
|
+
import type { OpenAIInput, AzureOpenAIInput, LegacyOpenAIInput } from "../types.js";
|
|
5
|
+
export declare class AzureOpenAI extends OpenAI {
|
|
6
|
+
get lc_aliases(): Record<string, string>;
|
|
7
|
+
constructor(fields?: Partial<OpenAIInput> & {
|
|
8
|
+
openAIApiKey?: string;
|
|
9
|
+
openAIApiVersion?: string;
|
|
10
|
+
openAIBasePath?: string;
|
|
11
|
+
deploymentName?: string;
|
|
12
|
+
} & Partial<AzureOpenAIInput> & BaseLLMParams & {
|
|
13
|
+
configuration?: ClientOptions & LegacyOpenAIInput;
|
|
14
|
+
});
|
|
15
|
+
toJSON(): any;
|
|
16
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { OpenAI } from "../llms.js";
|
|
2
|
+
export class AzureOpenAI extends OpenAI {
|
|
3
|
+
get lc_aliases() {
|
|
4
|
+
return {
|
|
5
|
+
openAIApiKey: "openai_api_key",
|
|
6
|
+
openAIApiVersion: "openai_api_version",
|
|
7
|
+
openAIBasePath: "openai_api_base",
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
constructor(fields) {
|
|
11
|
+
// assume the base URL does not contain "openai" nor "deployments" prefix
|
|
12
|
+
let basePath = fields?.openAIBasePath ?? "";
|
|
13
|
+
if (!basePath.endsWith("/"))
|
|
14
|
+
basePath += "/";
|
|
15
|
+
if (!basePath.endsWith("openai/deployments"))
|
|
16
|
+
basePath += "openai/deployments";
|
|
17
|
+
const newFields = fields ? { ...fields } : fields;
|
|
18
|
+
if (newFields) {
|
|
19
|
+
newFields.azureOpenAIBasePath = basePath;
|
|
20
|
+
newFields.azureOpenAIApiDeploymentName = newFields.deploymentName;
|
|
21
|
+
newFields.azureOpenAIApiKey = newFields.openAIApiKey;
|
|
22
|
+
newFields.azureOpenAIApiVersion = newFields.openAIApiVersion;
|
|
23
|
+
}
|
|
24
|
+
super(newFields);
|
|
25
|
+
}
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
27
|
+
toJSON() {
|
|
28
|
+
const json = super.toJSON();
|
|
29
|
+
function isRecord(obj) {
|
|
30
|
+
return typeof obj === "object" && obj != null;
|
|
31
|
+
}
|
|
32
|
+
if (isRecord(json) && isRecord(json.kwargs)) {
|
|
33
|
+
delete json.kwargs.azure_openai_base_path;
|
|
34
|
+
delete json.kwargs.azure_openai_api_deployment_name;
|
|
35
|
+
delete json.kwargs.azure_openai_api_key;
|
|
36
|
+
delete json.kwargs.azure_openai_api_version;
|
|
37
|
+
delete json.kwargs.azure_open_ai_base_path;
|
|
38
|
+
}
|
|
39
|
+
return json;
|
|
40
|
+
}
|
|
41
|
+
}
|
package/dist/embeddings.cjs
CHANGED
|
@@ -4,7 +4,7 @@ exports.OpenAIEmbeddings = void 0;
|
|
|
4
4
|
const openai_1 = require("openai");
|
|
5
5
|
const env_1 = require("@langchain/core/utils/env");
|
|
6
6
|
const embeddings_1 = require("@langchain/core/embeddings");
|
|
7
|
-
const
|
|
7
|
+
const chunk_array_1 = require("@langchain/core/utils/chunk_array");
|
|
8
8
|
const azure_js_1 = require("./utils/azure.cjs");
|
|
9
9
|
const openai_js_1 = require("./utils/openai.cjs");
|
|
10
10
|
/**
|
|
@@ -161,7 +161,7 @@ class OpenAIEmbeddings extends embeddings_1.Embeddings {
|
|
|
161
161
|
* @returns Promise that resolves to a 2D array of embeddings for each document.
|
|
162
162
|
*/
|
|
163
163
|
async embedDocuments(texts) {
|
|
164
|
-
const batches = (0,
|
|
164
|
+
const batches = (0, chunk_array_1.chunkArray)(this.stripNewLines ? texts.map((t) => t.replace(/\n/g, " ")) : texts, this.batchSize);
|
|
165
165
|
const batchRequests = batches.map((batch) => this.embeddingWithRetry({
|
|
166
166
|
model: this.modelName,
|
|
167
167
|
input: batch,
|
package/dist/embeddings.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OpenAI as OpenAIClient } from "openai";
|
|
2
2
|
import { getEnvironmentVariable } from "@langchain/core/utils/env";
|
|
3
3
|
import { Embeddings } from "@langchain/core/embeddings";
|
|
4
|
-
import { chunkArray } from "
|
|
4
|
+
import { chunkArray } from "@langchain/core/utils/chunk_array";
|
|
5
5
|
import { getEndpoint } from "./utils/azure.js";
|
|
6
6
|
import { wrapOpenAIClientError } from "./utils/openai.js";
|
|
7
7
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -19,7 +19,9 @@ var openai_1 = require("openai");
|
|
|
19
19
|
Object.defineProperty(exports, "OpenAIClient", { enumerable: true, get: function () { return openai_1.OpenAI; } });
|
|
20
20
|
Object.defineProperty(exports, "toFile", { enumerable: true, get: function () { return openai_1.toFile; } });
|
|
21
21
|
__exportStar(require("./chat_models.cjs"), exports);
|
|
22
|
+
__exportStar(require("./azure/chat_models.cjs"), exports);
|
|
22
23
|
__exportStar(require("./llms.cjs"), exports);
|
|
24
|
+
__exportStar(require("./azure/llms.cjs"), exports);
|
|
23
25
|
__exportStar(require("./embeddings.cjs"), exports);
|
|
24
26
|
__exportStar(require("./types.cjs"), exports);
|
|
25
27
|
__exportStar(require("./utils/openai.cjs"), exports);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { OpenAI as OpenAIClient, type ClientOptions, toFile } from "openai";
|
|
2
2
|
export * from "./chat_models.js";
|
|
3
|
+
export * from "./azure/chat_models.js";
|
|
3
4
|
export * from "./llms.js";
|
|
5
|
+
export * from "./azure/llms.js";
|
|
4
6
|
export * from "./embeddings.js";
|
|
5
7
|
export * from "./types.js";
|
|
6
8
|
export * from "./utils/openai.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { OpenAI as OpenAIClient, toFile } from "openai";
|
|
2
2
|
export * from "./chat_models.js";
|
|
3
|
+
export * from "./azure/chat_models.js";
|
|
3
4
|
export * from "./llms.js";
|
|
5
|
+
export * from "./azure/llms.js";
|
|
4
6
|
export * from "./embeddings.js";
|
|
5
7
|
export * from "./types.js";
|
|
6
8
|
export * from "./utils/openai.js";
|
package/dist/llms.cjs
CHANGED
|
@@ -6,8 +6,8 @@ const base_1 = require("@langchain/core/language_models/base");
|
|
|
6
6
|
const outputs_1 = require("@langchain/core/outputs");
|
|
7
7
|
const env_1 = require("@langchain/core/utils/env");
|
|
8
8
|
const llms_1 = require("@langchain/core/language_models/llms");
|
|
9
|
+
const chunk_array_1 = require("@langchain/core/utils/chunk_array");
|
|
9
10
|
const azure_js_1 = require("./utils/azure.cjs");
|
|
10
|
-
const chunk_js_1 = require("./utils/chunk.cjs");
|
|
11
11
|
const legacy_js_1 = require("./legacy.cjs");
|
|
12
12
|
Object.defineProperty(exports, "OpenAIChat", { enumerable: true, get: function () { return legacy_js_1.OpenAIChat; } });
|
|
13
13
|
const openai_js_1 = require("./utils/openai.cjs");
|
|
@@ -346,7 +346,7 @@ class OpenAI extends llms_1.BaseLLM {
|
|
|
346
346
|
* ```
|
|
347
347
|
*/
|
|
348
348
|
async _generate(prompts, options, runManager) {
|
|
349
|
-
const subPrompts = (0,
|
|
349
|
+
const subPrompts = (0, chunk_array_1.chunkArray)(prompts, this.batchSize);
|
|
350
350
|
const choices = [];
|
|
351
351
|
const tokenUsage = {};
|
|
352
352
|
const params = this.invocationParams(options);
|
|
@@ -429,7 +429,7 @@ class OpenAI extends llms_1.BaseLLM {
|
|
|
429
429
|
tokenUsage.totalTokens = (tokenUsage.totalTokens ?? 0) + totalTokens;
|
|
430
430
|
}
|
|
431
431
|
}
|
|
432
|
-
const generations = (0,
|
|
432
|
+
const generations = (0, chunk_array_1.chunkArray)(choices, this.n).map((promptChoices) => promptChoices.map((choice) => ({
|
|
433
433
|
text: choice.text ?? "",
|
|
434
434
|
generationInfo: {
|
|
435
435
|
finishReason: choice.finish_reason,
|
package/dist/llms.js
CHANGED
|
@@ -3,8 +3,8 @@ import { calculateMaxTokens } from "@langchain/core/language_models/base";
|
|
|
3
3
|
import { GenerationChunk } from "@langchain/core/outputs";
|
|
4
4
|
import { getEnvironmentVariable } from "@langchain/core/utils/env";
|
|
5
5
|
import { BaseLLM, } from "@langchain/core/language_models/llms";
|
|
6
|
+
import { chunkArray } from "@langchain/core/utils/chunk_array";
|
|
6
7
|
import { getEndpoint } from "./utils/azure.js";
|
|
7
|
-
import { chunkArray } from "./utils/chunk.js";
|
|
8
8
|
import { OpenAIChat } from "./legacy.js";
|
|
9
9
|
import { wrapOpenAIClientError } from "./utils/openai.js";
|
|
10
10
|
export { OpenAIChat };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { test, expect, jest } from "@jest/globals";
|
|
2
|
+
import { HumanMessage, ToolMessage } from "@langchain/core/messages";
|
|
3
|
+
import { InMemoryCache } from "@langchain/core/caches";
|
|
4
|
+
import { ChatOpenAI } from "../chat_models.js";
|
|
5
|
+
test("Test ChatOpenAI JSON mode", async () => {
|
|
6
|
+
const chat = new ChatOpenAI({
|
|
7
|
+
modelName: "gpt-3.5-turbo-1106",
|
|
8
|
+
maxTokens: 128,
|
|
9
|
+
}).bind({
|
|
10
|
+
response_format: {
|
|
11
|
+
type: "json_object",
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
const message = new HumanMessage("Hello!");
|
|
15
|
+
const res = await chat.invoke([["system", "Only return JSON"], message]);
|
|
16
|
+
console.log(JSON.stringify(res));
|
|
17
|
+
});
|
|
18
|
+
test("Test ChatOpenAI seed", async () => {
|
|
19
|
+
const chat = new ChatOpenAI({
|
|
20
|
+
modelName: "gpt-3.5-turbo-1106",
|
|
21
|
+
maxTokens: 128,
|
|
22
|
+
temperature: 1,
|
|
23
|
+
}).bind({
|
|
24
|
+
seed: 123454930394983,
|
|
25
|
+
});
|
|
26
|
+
const message = new HumanMessage("Say something random!");
|
|
27
|
+
const res = await chat.invoke([message]);
|
|
28
|
+
console.log(JSON.stringify(res));
|
|
29
|
+
const res2 = await chat.invoke([message]);
|
|
30
|
+
expect(res).toEqual(res2);
|
|
31
|
+
});
|
|
32
|
+
test("Test ChatOpenAI tool calling", async () => {
|
|
33
|
+
const chat = new ChatOpenAI({
|
|
34
|
+
modelName: "gpt-3.5-turbo-1106",
|
|
35
|
+
maxTokens: 128,
|
|
36
|
+
}).bind({
|
|
37
|
+
tools: [
|
|
38
|
+
{
|
|
39
|
+
type: "function",
|
|
40
|
+
function: {
|
|
41
|
+
name: "get_current_weather",
|
|
42
|
+
description: "Get the current weather in a given location",
|
|
43
|
+
parameters: {
|
|
44
|
+
type: "object",
|
|
45
|
+
properties: {
|
|
46
|
+
location: {
|
|
47
|
+
type: "string",
|
|
48
|
+
description: "The city and state, e.g. San Francisco, CA",
|
|
49
|
+
},
|
|
50
|
+
unit: { type: "string", enum: ["celsius", "fahrenheit"] },
|
|
51
|
+
},
|
|
52
|
+
required: ["location"],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
tool_choice: "auto",
|
|
58
|
+
});
|
|
59
|
+
const res = await chat.invoke([
|
|
60
|
+
["human", "What's the weather like in San Francisco, Tokyo, and Paris?"],
|
|
61
|
+
]);
|
|
62
|
+
console.log(JSON.stringify(res));
|
|
63
|
+
expect(res.additional_kwargs.tool_calls?.length).toBeGreaterThan(1);
|
|
64
|
+
});
|
|
65
|
+
test("Test ChatOpenAI tool calling with ToolMessages", async () => {
|
|
66
|
+
function getCurrentWeather(location) {
|
|
67
|
+
if (location.toLowerCase().includes("tokyo")) {
|
|
68
|
+
return JSON.stringify({ location, temperature: "10", unit: "celsius" });
|
|
69
|
+
}
|
|
70
|
+
else if (location.toLowerCase().includes("san francisco")) {
|
|
71
|
+
return JSON.stringify({
|
|
72
|
+
location,
|
|
73
|
+
temperature: "72",
|
|
74
|
+
unit: "fahrenheit",
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
return JSON.stringify({ location, temperature: "22", unit: "celsius" });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const chat = new ChatOpenAI({
|
|
82
|
+
modelName: "gpt-3.5-turbo-1106",
|
|
83
|
+
maxTokens: 128,
|
|
84
|
+
}).bind({
|
|
85
|
+
tools: [
|
|
86
|
+
{
|
|
87
|
+
type: "function",
|
|
88
|
+
function: {
|
|
89
|
+
name: "get_current_weather",
|
|
90
|
+
description: "Get the current weather in a given location",
|
|
91
|
+
parameters: {
|
|
92
|
+
type: "object",
|
|
93
|
+
properties: {
|
|
94
|
+
location: {
|
|
95
|
+
type: "string",
|
|
96
|
+
description: "The city and state, e.g. San Francisco, CA",
|
|
97
|
+
},
|
|
98
|
+
unit: { type: "string", enum: ["celsius", "fahrenheit"] },
|
|
99
|
+
},
|
|
100
|
+
required: ["location"],
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
tool_choice: "auto",
|
|
106
|
+
});
|
|
107
|
+
const res = await chat.invoke([
|
|
108
|
+
["human", "What's the weather like in San Francisco, Tokyo, and Paris?"],
|
|
109
|
+
]);
|
|
110
|
+
console.log(JSON.stringify(res));
|
|
111
|
+
expect(res.additional_kwargs.tool_calls?.length).toBeGreaterThan(1);
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
113
|
+
const toolMessages = res.additional_kwargs.tool_calls.map((toolCall) => new ToolMessage({
|
|
114
|
+
tool_call_id: toolCall.id,
|
|
115
|
+
name: toolCall.function.name,
|
|
116
|
+
content: getCurrentWeather(JSON.parse(toolCall.function.arguments).location),
|
|
117
|
+
}));
|
|
118
|
+
const finalResponse = await chat.invoke([
|
|
119
|
+
["human", "What's the weather like in San Francisco, Tokyo, and Paris?"],
|
|
120
|
+
res,
|
|
121
|
+
...toolMessages,
|
|
122
|
+
]);
|
|
123
|
+
console.log(finalResponse);
|
|
124
|
+
});
|
|
125
|
+
test("Test ChatOpenAI tool calling with streaming", async () => {
|
|
126
|
+
const chat = new ChatOpenAI({
|
|
127
|
+
modelName: "gpt-3.5-turbo-1106",
|
|
128
|
+
maxTokens: 256,
|
|
129
|
+
}).bind({
|
|
130
|
+
tools: [
|
|
131
|
+
{
|
|
132
|
+
type: "function",
|
|
133
|
+
function: {
|
|
134
|
+
name: "get_current_weather",
|
|
135
|
+
description: "Get the current weather in a given location",
|
|
136
|
+
parameters: {
|
|
137
|
+
type: "object",
|
|
138
|
+
properties: {
|
|
139
|
+
location: {
|
|
140
|
+
type: "string",
|
|
141
|
+
description: "The city and state, e.g. San Francisco, CA",
|
|
142
|
+
},
|
|
143
|
+
unit: { type: "string", enum: ["celsius", "fahrenheit"] },
|
|
144
|
+
},
|
|
145
|
+
required: ["location"],
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
tool_choice: "auto",
|
|
151
|
+
});
|
|
152
|
+
const stream = await chat.stream([
|
|
153
|
+
["human", "What's the weather like in San Francisco, Tokyo, and Paris?"],
|
|
154
|
+
]);
|
|
155
|
+
let finalChunk;
|
|
156
|
+
const chunks = [];
|
|
157
|
+
for await (const chunk of stream) {
|
|
158
|
+
console.log(chunk.additional_kwargs.tool_calls);
|
|
159
|
+
chunks.push(chunk);
|
|
160
|
+
if (!finalChunk) {
|
|
161
|
+
finalChunk = chunk;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
finalChunk = finalChunk.concat(chunk);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
expect(chunks.length).toBeGreaterThan(1);
|
|
168
|
+
console.log(finalChunk?.additional_kwargs.tool_calls);
|
|
169
|
+
expect(finalChunk?.additional_kwargs.tool_calls?.length).toBeGreaterThan(1);
|
|
170
|
+
});
|
|
171
|
+
test("ChatOpenAI in JSON mode can cache generations", async () => {
|
|
172
|
+
const memoryCache = new InMemoryCache();
|
|
173
|
+
const lookupSpy = jest.spyOn(memoryCache, "lookup");
|
|
174
|
+
const updateSpy = jest.spyOn(memoryCache, "update");
|
|
175
|
+
const chat = new ChatOpenAI({
|
|
176
|
+
modelName: "gpt-3.5-turbo-1106",
|
|
177
|
+
temperature: 1,
|
|
178
|
+
cache: memoryCache,
|
|
179
|
+
}).bind({
|
|
180
|
+
response_format: {
|
|
181
|
+
type: "json_object",
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
const message = new HumanMessage("Respond with a JSON object containing arbitrary fields.");
|
|
185
|
+
const res = await chat.invoke([message]);
|
|
186
|
+
console.log(res);
|
|
187
|
+
const res2 = await chat.invoke([message]);
|
|
188
|
+
console.log(res2);
|
|
189
|
+
expect(res).toEqual(res2);
|
|
190
|
+
expect(lookupSpy).toHaveBeenCalledTimes(2);
|
|
191
|
+
expect(updateSpy).toHaveBeenCalledTimes(1);
|
|
192
|
+
lookupSpy.mockRestore();
|
|
193
|
+
updateSpy.mockRestore();
|
|
194
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { test } from "@jest/globals";
|
|
2
|
+
import { HumanMessage } from "@langchain/core/messages";
|
|
3
|
+
import * as fs from "node:fs/promises";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
import { ChatOpenAI } from "../chat_models.js";
|
|
7
|
+
test("Test ChatOpenAI with a file", async () => {
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
const imageData = await fs.readFile(path.join(__dirname, "/data/hotdog.jpg"));
|
|
11
|
+
const chat = new ChatOpenAI({
|
|
12
|
+
modelName: "gpt-4-vision-preview",
|
|
13
|
+
maxTokens: 1024,
|
|
14
|
+
});
|
|
15
|
+
const message = new HumanMessage({
|
|
16
|
+
content: [
|
|
17
|
+
{
|
|
18
|
+
type: "text",
|
|
19
|
+
text: "What's in this image?",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
type: "image_url",
|
|
23
|
+
image_url: {
|
|
24
|
+
url: `data:image/jpeg;base64,${imageData.toString("base64")}`,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
});
|
|
29
|
+
const res = await chat.invoke([message]);
|
|
30
|
+
console.log({ res });
|
|
31
|
+
});
|
|
32
|
+
test("Test ChatOpenAI with a URL", async () => {
|
|
33
|
+
const chat = new ChatOpenAI({
|
|
34
|
+
modelName: "gpt-4-vision-preview",
|
|
35
|
+
maxTokens: 1024,
|
|
36
|
+
});
|
|
37
|
+
const message = new HumanMessage({
|
|
38
|
+
content: [
|
|
39
|
+
{
|
|
40
|
+
type: "text",
|
|
41
|
+
text: "What does this image say?",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
type: "image_url",
|
|
45
|
+
image_url: "https://www.freecodecamp.org/news/content/images/2023/05/Screenshot-2023-05-29-at-5.40.38-PM.png",
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
});
|
|
49
|
+
const res = await chat.invoke([message]);
|
|
50
|
+
console.log({ res });
|
|
51
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|