langchain 0.0.183 → 0.0.185
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/agents/format_scratchpad/openai_tools.cjs +1 -0
- package/agents/format_scratchpad/openai_tools.d.ts +1 -0
- package/agents/format_scratchpad/openai_tools.js +1 -0
- package/dist/agents/agent.cjs +19 -13
- package/dist/agents/agent.d.ts +16 -17
- package/dist/agents/agent.js +17 -11
- package/dist/agents/executor.d.ts +10 -16
- package/dist/agents/format_scratchpad/openai_tools.cjs +19 -0
- package/dist/agents/format_scratchpad/openai_tools.d.ts +3 -0
- package/dist/agents/format_scratchpad/openai_tools.js +15 -0
- package/dist/agents/openai/output_parser.cjs +66 -1
- package/dist/agents/openai/output_parser.d.ts +26 -2
- package/dist/agents/openai/output_parser.js +65 -1
- package/dist/agents/structured_chat/index.cjs +1 -2
- package/dist/agents/structured_chat/index.d.ts +2 -0
- package/dist/agents/structured_chat/index.js +1 -2
- package/dist/agents/toolkits/aws_sfn.d.ts +1 -4
- package/dist/agents/toolkits/conversational_retrieval/openai_functions.d.ts +1 -1
- package/dist/agents/toolkits/json/json.d.ts +1 -4
- package/dist/agents/toolkits/openapi/openapi.d.ts +1 -4
- package/dist/agents/toolkits/sql/sql.d.ts +1 -4
- package/dist/agents/toolkits/vectorstore/vectorstore.d.ts +2 -8
- package/dist/agents/types.cjs +8 -1
- package/dist/agents/types.d.ts +11 -5
- package/dist/agents/types.js +6 -0
- package/dist/document_loaders/fs/pdf.cjs +17 -3
- package/dist/document_loaders/fs/pdf.js +17 -3
- package/dist/document_loaders/web/apify_dataset.cjs +12 -6
- package/dist/document_loaders/web/apify_dataset.d.ts +9 -6
- package/dist/document_loaders/web/apify_dataset.js +12 -6
- package/dist/document_loaders/web/pdf.cjs +17 -3
- package/dist/document_loaders/web/pdf.js +17 -3
- package/dist/document_loaders/web/puppeteer.cjs +37 -0
- package/dist/document_loaders/web/puppeteer.d.ts +17 -0
- package/dist/document_loaders/web/puppeteer.js +37 -0
- package/dist/experimental/openai_assistant/index.cjs +221 -0
- package/dist/experimental/openai_assistant/index.d.ts +36 -0
- package/dist/experimental/openai_assistant/index.js +217 -0
- package/dist/experimental/openai_assistant/schema.cjs +2 -0
- package/dist/experimental/openai_assistant/schema.d.ts +12 -0
- package/dist/experimental/openai_assistant/schema.js +1 -0
- package/dist/experimental/plan_and_execute/agent_executor.cjs +28 -2
- package/dist/experimental/plan_and_execute/agent_executor.d.ts +10 -3
- package/dist/experimental/plan_and_execute/agent_executor.js +26 -1
- package/dist/experimental/plan_and_execute/prompt.d.ts +2 -1
- package/dist/load/import_map.cjs +4 -2
- package/dist/load/import_map.d.ts +2 -0
- package/dist/load/import_map.js +2 -0
- package/dist/prompts/chat.cjs +22 -1
- package/dist/prompts/chat.d.ts +1 -0
- package/dist/prompts/chat.js +22 -1
- package/dist/schema/index.d.ts +1 -0
- package/dist/tools/convert_to_openai.cjs +14 -2
- package/dist/tools/convert_to_openai.d.ts +1 -0
- package/dist/tools/convert_to_openai.js +11 -0
- package/dist/tools/index.cjs +2 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.js +1 -1
- package/dist/vectorstores/momento_vector_index.cjs +1 -1
- package/dist/vectorstores/momento_vector_index.js +1 -1
- package/dist/vectorstores/pinecone.cjs +4 -1
- package/dist/vectorstores/pinecone.d.ts +2 -1
- package/dist/vectorstores/pinecone.js +4 -1
- package/experimental/openai_assistant.cjs +1 -0
- package/experimental/openai_assistant.d.ts +1 -0
- package/experimental/openai_assistant.js +1 -0
- package/package.json +24 -8
|
@@ -59,9 +59,23 @@ class PDFLoader extends buffer_js_1.BufferLoader {
|
|
|
59
59
|
if (content.items.length === 0) {
|
|
60
60
|
continue;
|
|
61
61
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
// Eliminate excessive newlines
|
|
63
|
+
// Source: https://github.com/albertcui/pdf-parse/blob/7086fc1cc9058545cdf41dd0646d6ae5832c7107/lib/pdf-parse.js#L16
|
|
64
|
+
let lastY;
|
|
65
|
+
const textItems = [];
|
|
66
|
+
for (const item of content.items) {
|
|
67
|
+
if ("str" in item) {
|
|
68
|
+
if (lastY === item.transform[5] || !lastY) {
|
|
69
|
+
textItems.push(item.str);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
textItems.push(`\n${item.str}`);
|
|
73
|
+
}
|
|
74
|
+
// eslint-disable-next-line prefer-destructuring
|
|
75
|
+
lastY = item.transform[5];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const text = textItems.join(" ");
|
|
65
79
|
documents.push(new document_js_1.Document({
|
|
66
80
|
pageContent: text,
|
|
67
81
|
metadata: {
|
|
@@ -56,9 +56,23 @@ export class PDFLoader extends BufferLoader {
|
|
|
56
56
|
if (content.items.length === 0) {
|
|
57
57
|
continue;
|
|
58
58
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
// Eliminate excessive newlines
|
|
60
|
+
// Source: https://github.com/albertcui/pdf-parse/blob/7086fc1cc9058545cdf41dd0646d6ae5832c7107/lib/pdf-parse.js#L16
|
|
61
|
+
let lastY;
|
|
62
|
+
const textItems = [];
|
|
63
|
+
for (const item of content.items) {
|
|
64
|
+
if ("str" in item) {
|
|
65
|
+
if (lastY === item.transform[5] || !lastY) {
|
|
66
|
+
textItems.push(item.str);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
textItems.push(`\n${item.str}`);
|
|
70
|
+
}
|
|
71
|
+
// eslint-disable-next-line prefer-destructuring
|
|
72
|
+
lastY = item.transform[5];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const text = textItems.join(" ");
|
|
62
76
|
documents.push(new Document({
|
|
63
77
|
pageContent: text,
|
|
64
78
|
metadata: {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.ApifyDatasetLoader = void 0;
|
|
5
5
|
const apify_client_1 = require("apify-client");
|
|
6
|
+
const async_caller_js_1 = require("../../util/async_caller.cjs");
|
|
6
7
|
const base_js_1 = require("../base.cjs");
|
|
7
8
|
const env_js_1 = require("../../util/env.cjs");
|
|
8
9
|
/**
|
|
@@ -31,13 +32,18 @@ class ApifyDatasetLoader extends base_js_1.BaseDocumentLoader {
|
|
|
31
32
|
writable: true,
|
|
32
33
|
value: void 0
|
|
33
34
|
});
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
Object.defineProperty(this, "caller", {
|
|
36
|
+
enumerable: true,
|
|
37
|
+
configurable: true,
|
|
38
|
+
writable: true,
|
|
39
|
+
value: void 0
|
|
38
40
|
});
|
|
41
|
+
const { clientOptions, datasetMappingFunction, ...asyncCallerParams } = config;
|
|
42
|
+
const token = ApifyDatasetLoader._getApifyApiToken(clientOptions);
|
|
43
|
+
this.apifyClient = new apify_client_1.ApifyClient({ ...clientOptions, token });
|
|
39
44
|
this.datasetId = datasetId;
|
|
40
|
-
this.datasetMappingFunction =
|
|
45
|
+
this.datasetMappingFunction = datasetMappingFunction;
|
|
46
|
+
this.caller = new async_caller_js_1.AsyncCaller(asyncCallerParams);
|
|
41
47
|
}
|
|
42
48
|
static _getApifyApiToken(config) {
|
|
43
49
|
return config?.token ?? (0, env_js_1.getEnvironmentVariable)("APIFY_API_TOKEN");
|
|
@@ -50,7 +56,7 @@ class ApifyDatasetLoader extends base_js_1.BaseDocumentLoader {
|
|
|
50
56
|
*/
|
|
51
57
|
async load() {
|
|
52
58
|
const datasetItems = (await this.apifyClient.dataset(this.datasetId).listItems({ clean: true })).items;
|
|
53
|
-
return datasetItems.map(this.datasetMappingFunction);
|
|
59
|
+
return await Promise.all(datasetItems.map((item) => this.caller.call(async () => this.datasetMappingFunction(item))));
|
|
54
60
|
}
|
|
55
61
|
/**
|
|
56
62
|
* Create an ApifyDatasetLoader by calling an Actor on the Apify platform and waiting for its results to be ready.
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { ActorCallOptions, ApifyClient, ApifyClientOptions, TaskCallOptions } from "apify-client";
|
|
2
|
+
import { AsyncCaller, AsyncCallerParams } from "../../util/async_caller.js";
|
|
2
3
|
import { BaseDocumentLoader, DocumentLoader } from "../base.js";
|
|
3
4
|
import { Document } from "../../document.js";
|
|
4
5
|
/**
|
|
5
6
|
* A type that represents a function that takes a single object (an Apify
|
|
6
7
|
* dataset item) and converts it to an instance of the Document class.
|
|
7
8
|
*/
|
|
8
|
-
export type ApifyDatasetMappingFunction<Metadata extends Record<string, any>> = (item: Record<string | number, unknown>) => Document<Metadata
|
|
9
|
+
export type ApifyDatasetMappingFunction<Metadata extends Record<string, any>> = (item: Record<string | number, unknown>) => Document<Metadata> | Promise<Document<Metadata>>;
|
|
10
|
+
export interface ApifyDatasetLoaderConfig<Metadata extends Record<string, any>> extends AsyncCallerParams {
|
|
11
|
+
datasetMappingFunction: ApifyDatasetMappingFunction<Metadata>;
|
|
12
|
+
clientOptions?: ApifyClientOptions;
|
|
13
|
+
}
|
|
9
14
|
/**
|
|
10
15
|
* A class that extends the BaseDocumentLoader and implements the
|
|
11
16
|
* DocumentLoader interface. It represents a document loader that loads
|
|
@@ -14,11 +19,9 @@ export type ApifyDatasetMappingFunction<Metadata extends Record<string, any>> =
|
|
|
14
19
|
export declare class ApifyDatasetLoader<Metadata extends Record<string, any>> extends BaseDocumentLoader implements DocumentLoader {
|
|
15
20
|
protected apifyClient: ApifyClient;
|
|
16
21
|
protected datasetId: string;
|
|
17
|
-
protected datasetMappingFunction:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
clientOptions?: ApifyClientOptions;
|
|
21
|
-
});
|
|
22
|
+
protected datasetMappingFunction: ApifyDatasetMappingFunction<Metadata>;
|
|
23
|
+
protected caller: AsyncCaller;
|
|
24
|
+
constructor(datasetId: string, config: ApifyDatasetLoaderConfig<Metadata>);
|
|
22
25
|
private static _getApifyApiToken;
|
|
23
26
|
/**
|
|
24
27
|
* Retrieves the dataset items from the Apify platform and applies the
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { ApifyClient, } from "apify-client";
|
|
3
|
+
import { AsyncCaller } from "../../util/async_caller.js";
|
|
3
4
|
import { BaseDocumentLoader } from "../base.js";
|
|
4
5
|
import { getEnvironmentVariable } from "../../util/env.js";
|
|
5
6
|
/**
|
|
@@ -28,13 +29,18 @@ export class ApifyDatasetLoader extends BaseDocumentLoader {
|
|
|
28
29
|
writable: true,
|
|
29
30
|
value: void 0
|
|
30
31
|
});
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
Object.defineProperty(this, "caller", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
value: void 0
|
|
35
37
|
});
|
|
38
|
+
const { clientOptions, datasetMappingFunction, ...asyncCallerParams } = config;
|
|
39
|
+
const token = ApifyDatasetLoader._getApifyApiToken(clientOptions);
|
|
40
|
+
this.apifyClient = new ApifyClient({ ...clientOptions, token });
|
|
36
41
|
this.datasetId = datasetId;
|
|
37
|
-
this.datasetMappingFunction =
|
|
42
|
+
this.datasetMappingFunction = datasetMappingFunction;
|
|
43
|
+
this.caller = new AsyncCaller(asyncCallerParams);
|
|
38
44
|
}
|
|
39
45
|
static _getApifyApiToken(config) {
|
|
40
46
|
return config?.token ?? getEnvironmentVariable("APIFY_API_TOKEN");
|
|
@@ -47,7 +53,7 @@ export class ApifyDatasetLoader extends BaseDocumentLoader {
|
|
|
47
53
|
*/
|
|
48
54
|
async load() {
|
|
49
55
|
const datasetItems = (await this.apifyClient.dataset(this.datasetId).listItems({ clean: true })).items;
|
|
50
|
-
return datasetItems.map(this.datasetMappingFunction);
|
|
56
|
+
return await Promise.all(datasetItems.map((item) => this.caller.call(async () => this.datasetMappingFunction(item))));
|
|
51
57
|
}
|
|
52
58
|
/**
|
|
53
59
|
* Create an ApifyDatasetLoader by calling an Actor on the Apify platform and waiting for its results to be ready.
|
|
@@ -52,9 +52,23 @@ class WebPDFLoader extends base_js_1.BaseDocumentLoader {
|
|
|
52
52
|
if (content.items.length === 0) {
|
|
53
53
|
continue;
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
// Eliminate excessive newlines
|
|
56
|
+
// Source: https://github.com/albertcui/pdf-parse/blob/7086fc1cc9058545cdf41dd0646d6ae5832c7107/lib/pdf-parse.js#L16
|
|
57
|
+
let lastY;
|
|
58
|
+
const textItems = [];
|
|
59
|
+
for (const item of content.items) {
|
|
60
|
+
if ("str" in item) {
|
|
61
|
+
if (lastY === item.transform[5] || !lastY) {
|
|
62
|
+
textItems.push(item.str);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
textItems.push(`\n${item.str}`);
|
|
66
|
+
}
|
|
67
|
+
// eslint-disable-next-line prefer-destructuring
|
|
68
|
+
lastY = item.transform[5];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const text = textItems.join(" ");
|
|
58
72
|
documents.push(new document_js_1.Document({
|
|
59
73
|
pageContent: text,
|
|
60
74
|
metadata: {
|
|
@@ -49,9 +49,23 @@ export class WebPDFLoader extends BaseDocumentLoader {
|
|
|
49
49
|
if (content.items.length === 0) {
|
|
50
50
|
continue;
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
// Eliminate excessive newlines
|
|
53
|
+
// Source: https://github.com/albertcui/pdf-parse/blob/7086fc1cc9058545cdf41dd0646d6ae5832c7107/lib/pdf-parse.js#L16
|
|
54
|
+
let lastY;
|
|
55
|
+
const textItems = [];
|
|
56
|
+
for (const item of content.items) {
|
|
57
|
+
if ("str" in item) {
|
|
58
|
+
if (lastY === item.transform[5] || !lastY) {
|
|
59
|
+
textItems.push(item.str);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
textItems.push(`\n${item.str}`);
|
|
63
|
+
}
|
|
64
|
+
// eslint-disable-next-line prefer-destructuring
|
|
65
|
+
lastY = item.transform[5];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const text = textItems.join(" ");
|
|
55
69
|
documents.push(new Document({
|
|
56
70
|
pageContent: text,
|
|
57
71
|
metadata: {
|
|
@@ -63,6 +63,43 @@ class PuppeteerWebBaseLoader extends base_js_1.BaseDocumentLoader {
|
|
|
63
63
|
const metadata = { source: this.webPath };
|
|
64
64
|
return [new document_js_1.Document({ pageContent: text, metadata })];
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Static class method used to screenshot a web page and return
|
|
68
|
+
* it as a {@link Document} object where the pageContent property
|
|
69
|
+
* is the screenshot encoded in base64.
|
|
70
|
+
*
|
|
71
|
+
* @param {string} url
|
|
72
|
+
* @param {PuppeteerWebBaseLoaderOptions} options
|
|
73
|
+
* @returns {Document} A document object containing the screenshot of the page encoded in base64.
|
|
74
|
+
*/
|
|
75
|
+
static async _screenshot(url, options) {
|
|
76
|
+
const { launch } = await PuppeteerWebBaseLoader.imports();
|
|
77
|
+
const browser = await launch({
|
|
78
|
+
headless: true,
|
|
79
|
+
defaultViewport: null,
|
|
80
|
+
ignoreDefaultArgs: ["--disable-extensions"],
|
|
81
|
+
...options?.launchOptions,
|
|
82
|
+
});
|
|
83
|
+
const page = await browser.newPage();
|
|
84
|
+
await page.goto(url, {
|
|
85
|
+
timeout: 180000,
|
|
86
|
+
waitUntil: "domcontentloaded",
|
|
87
|
+
...options?.gotoOptions,
|
|
88
|
+
});
|
|
89
|
+
const screenshot = await page.screenshot();
|
|
90
|
+
const base64 = screenshot.toString("base64");
|
|
91
|
+
const metadata = { source: url };
|
|
92
|
+
return new document_js_1.Document({ pageContent: base64, metadata });
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Screenshot a web page and return it as a {@link Document} object where
|
|
96
|
+
* the pageContent property is the screenshot encoded in base64.
|
|
97
|
+
*
|
|
98
|
+
* @returns {Promise<Document>} A document object containing the screenshot of the page encoded in base64.
|
|
99
|
+
*/
|
|
100
|
+
async screenshot() {
|
|
101
|
+
return PuppeteerWebBaseLoader._screenshot(this.webPath, this.options);
|
|
102
|
+
}
|
|
66
103
|
/**
|
|
67
104
|
* Static method that imports the necessary Puppeteer modules. It returns
|
|
68
105
|
* a Promise that resolves to an object containing the imported modules.
|
|
@@ -40,6 +40,23 @@ export declare class PuppeteerWebBaseLoader extends BaseDocumentLoader implement
|
|
|
40
40
|
* @returns Promise that resolves to an array of Document objects.
|
|
41
41
|
*/
|
|
42
42
|
load(): Promise<Document[]>;
|
|
43
|
+
/**
|
|
44
|
+
* Static class method used to screenshot a web page and return
|
|
45
|
+
* it as a {@link Document} object where the pageContent property
|
|
46
|
+
* is the screenshot encoded in base64.
|
|
47
|
+
*
|
|
48
|
+
* @param {string} url
|
|
49
|
+
* @param {PuppeteerWebBaseLoaderOptions} options
|
|
50
|
+
* @returns {Document} A document object containing the screenshot of the page encoded in base64.
|
|
51
|
+
*/
|
|
52
|
+
static _screenshot(url: string, options?: PuppeteerWebBaseLoaderOptions): Promise<Document>;
|
|
53
|
+
/**
|
|
54
|
+
* Screenshot a web page and return it as a {@link Document} object where
|
|
55
|
+
* the pageContent property is the screenshot encoded in base64.
|
|
56
|
+
*
|
|
57
|
+
* @returns {Promise<Document>} A document object containing the screenshot of the page encoded in base64.
|
|
58
|
+
*/
|
|
59
|
+
screenshot(): Promise<Document>;
|
|
43
60
|
/**
|
|
44
61
|
* Static method that imports the necessary Puppeteer modules. It returns
|
|
45
62
|
* a Promise that resolves to an object containing the imported modules.
|
|
@@ -60,6 +60,43 @@ export class PuppeteerWebBaseLoader extends BaseDocumentLoader {
|
|
|
60
60
|
const metadata = { source: this.webPath };
|
|
61
61
|
return [new Document({ pageContent: text, metadata })];
|
|
62
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Static class method used to screenshot a web page and return
|
|
65
|
+
* it as a {@link Document} object where the pageContent property
|
|
66
|
+
* is the screenshot encoded in base64.
|
|
67
|
+
*
|
|
68
|
+
* @param {string} url
|
|
69
|
+
* @param {PuppeteerWebBaseLoaderOptions} options
|
|
70
|
+
* @returns {Document} A document object containing the screenshot of the page encoded in base64.
|
|
71
|
+
*/
|
|
72
|
+
static async _screenshot(url, options) {
|
|
73
|
+
const { launch } = await PuppeteerWebBaseLoader.imports();
|
|
74
|
+
const browser = await launch({
|
|
75
|
+
headless: true,
|
|
76
|
+
defaultViewport: null,
|
|
77
|
+
ignoreDefaultArgs: ["--disable-extensions"],
|
|
78
|
+
...options?.launchOptions,
|
|
79
|
+
});
|
|
80
|
+
const page = await browser.newPage();
|
|
81
|
+
await page.goto(url, {
|
|
82
|
+
timeout: 180000,
|
|
83
|
+
waitUntil: "domcontentloaded",
|
|
84
|
+
...options?.gotoOptions,
|
|
85
|
+
});
|
|
86
|
+
const screenshot = await page.screenshot();
|
|
87
|
+
const base64 = screenshot.toString("base64");
|
|
88
|
+
const metadata = { source: url };
|
|
89
|
+
return new Document({ pageContent: base64, metadata });
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Screenshot a web page and return it as a {@link Document} object where
|
|
93
|
+
* the pageContent property is the screenshot encoded in base64.
|
|
94
|
+
*
|
|
95
|
+
* @returns {Promise<Document>} A document object containing the screenshot of the page encoded in base64.
|
|
96
|
+
*/
|
|
97
|
+
async screenshot() {
|
|
98
|
+
return PuppeteerWebBaseLoader._screenshot(this.webPath, this.options);
|
|
99
|
+
}
|
|
63
100
|
/**
|
|
64
101
|
* Static method that imports the necessary Puppeteer modules. It returns
|
|
65
102
|
* a Promise that resolves to an object containing the imported modules.
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpenAIAssistantRunnable = void 0;
|
|
4
|
+
const openai_1 = require("openai");
|
|
5
|
+
const base_js_1 = require("../../schema/runnable/base.cjs");
|
|
6
|
+
const time_js_1 = require("../../util/time.cjs");
|
|
7
|
+
const base_js_2 = require("../../tools/base.cjs");
|
|
8
|
+
const convert_to_openai_js_1 = require("../../tools/convert_to_openai.cjs");
|
|
9
|
+
class OpenAIAssistantRunnable extends base_js_1.Runnable {
|
|
10
|
+
constructor(fields) {
|
|
11
|
+
super(fields);
|
|
12
|
+
Object.defineProperty(this, "lc_namespace", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
configurable: true,
|
|
15
|
+
writable: true,
|
|
16
|
+
value: ["langchain", "experimental", "openai_assistant"]
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(this, "client", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
configurable: true,
|
|
21
|
+
writable: true,
|
|
22
|
+
value: void 0
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(this, "assistantId", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
configurable: true,
|
|
27
|
+
writable: true,
|
|
28
|
+
value: void 0
|
|
29
|
+
});
|
|
30
|
+
Object.defineProperty(this, "pollIntervalMs", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
configurable: true,
|
|
33
|
+
writable: true,
|
|
34
|
+
value: 1000
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(this, "asAgent", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
configurable: true,
|
|
39
|
+
writable: true,
|
|
40
|
+
value: void 0
|
|
41
|
+
});
|
|
42
|
+
this.client = fields.client ?? new openai_1.OpenAI(fields?.clientOptions);
|
|
43
|
+
this.assistantId = fields.assistantId;
|
|
44
|
+
this.asAgent = fields.asAgent ?? this.asAgent;
|
|
45
|
+
}
|
|
46
|
+
static async createAssistant({ model, name, instructions, tools, client, clientOptions, asAgent, pollIntervalMs, }) {
|
|
47
|
+
const formattedTools = tools?.map((tool) => {
|
|
48
|
+
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
49
|
+
if (tool instanceof base_js_2.StructuredTool) {
|
|
50
|
+
return (0, convert_to_openai_js_1.formatToOpenAIAssistantTool)(tool);
|
|
51
|
+
}
|
|
52
|
+
return tool;
|
|
53
|
+
}) ?? [];
|
|
54
|
+
const oaiClient = client ?? new openai_1.OpenAI(clientOptions);
|
|
55
|
+
const assistant = await oaiClient.beta.assistants.create({
|
|
56
|
+
name,
|
|
57
|
+
instructions,
|
|
58
|
+
tools: formattedTools,
|
|
59
|
+
model,
|
|
60
|
+
});
|
|
61
|
+
return new this({
|
|
62
|
+
client: oaiClient,
|
|
63
|
+
assistantId: assistant.id,
|
|
64
|
+
asAgent,
|
|
65
|
+
pollIntervalMs,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
async invoke(input, _options) {
|
|
69
|
+
let run;
|
|
70
|
+
if (this.asAgent && input.steps && input.steps.length > 0) {
|
|
71
|
+
const parsedStepsInput = await this._parseStepsInput(input);
|
|
72
|
+
run = await this.client.beta.threads.runs.submitToolOutputs(parsedStepsInput.threadId, parsedStepsInput.runId, {
|
|
73
|
+
tool_outputs: parsedStepsInput.toolOutputs,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else if (!("threadId" in input)) {
|
|
77
|
+
const thread = {
|
|
78
|
+
messages: [
|
|
79
|
+
{
|
|
80
|
+
role: "user",
|
|
81
|
+
content: input.content,
|
|
82
|
+
file_ids: input.fileIds,
|
|
83
|
+
metadata: input.messagesMetadata,
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
metadata: input.threadMetadata,
|
|
87
|
+
};
|
|
88
|
+
run = await this._createThreadAndRun({
|
|
89
|
+
...input,
|
|
90
|
+
thread,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
else if (!("runId" in input)) {
|
|
94
|
+
await this.client.beta.threads.messages.create(input.threadId, {
|
|
95
|
+
content: input.content,
|
|
96
|
+
role: "user",
|
|
97
|
+
file_ids: input.file_ids,
|
|
98
|
+
metadata: input.messagesMetadata,
|
|
99
|
+
});
|
|
100
|
+
run = await this._createRun(input);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
// Submitting tool outputs to an existing run, outside the AgentExecutor
|
|
104
|
+
// framework.
|
|
105
|
+
run = await this.client.beta.threads.runs.submitToolOutputs(input.runId, input.threadId, {
|
|
106
|
+
tool_outputs: input.toolOutputs,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return this._getResponse(run.id, run.thread_id);
|
|
110
|
+
}
|
|
111
|
+
async _parseStepsInput(input) {
|
|
112
|
+
const { action: { runId, threadId }, } = input.steps[input.steps.length - 1];
|
|
113
|
+
const run = await this._waitForRun(runId, threadId);
|
|
114
|
+
const toolCalls = run.required_action?.submit_tool_outputs.tool_calls;
|
|
115
|
+
if (!toolCalls) {
|
|
116
|
+
return input;
|
|
117
|
+
}
|
|
118
|
+
const toolOutputs = toolCalls.flatMap((toolCall) => {
|
|
119
|
+
const matchedAction = input.steps.find((step) => step.action.toolCallId === toolCall.id);
|
|
120
|
+
return matchedAction
|
|
121
|
+
? [
|
|
122
|
+
{
|
|
123
|
+
output: matchedAction.observation,
|
|
124
|
+
tool_call_id: matchedAction.action.toolCallId,
|
|
125
|
+
},
|
|
126
|
+
]
|
|
127
|
+
: [];
|
|
128
|
+
});
|
|
129
|
+
return { toolOutputs, runId, threadId };
|
|
130
|
+
}
|
|
131
|
+
async _createRun({ instructions, model, tools, metadata, threadId, }) {
|
|
132
|
+
const run = this.client.beta.threads.runs.create(threadId, {
|
|
133
|
+
assistant_id: this.assistantId,
|
|
134
|
+
instructions,
|
|
135
|
+
model,
|
|
136
|
+
tools,
|
|
137
|
+
metadata,
|
|
138
|
+
});
|
|
139
|
+
return run;
|
|
140
|
+
}
|
|
141
|
+
async _createThreadAndRun(input) {
|
|
142
|
+
const params = [
|
|
143
|
+
"instructions",
|
|
144
|
+
"model",
|
|
145
|
+
"tools",
|
|
146
|
+
"run_metadata",
|
|
147
|
+
]
|
|
148
|
+
.filter((key) => key in input)
|
|
149
|
+
.reduce((obj, key) => {
|
|
150
|
+
const newObj = obj;
|
|
151
|
+
newObj[key] = input[key];
|
|
152
|
+
return newObj;
|
|
153
|
+
}, {});
|
|
154
|
+
const run = this.client.beta.threads.createAndRun({
|
|
155
|
+
...params,
|
|
156
|
+
thread: input.thread,
|
|
157
|
+
assistant_id: this.assistantId,
|
|
158
|
+
});
|
|
159
|
+
return run;
|
|
160
|
+
}
|
|
161
|
+
async _waitForRun(runId, threadId) {
|
|
162
|
+
let inProgress = true;
|
|
163
|
+
let run = {};
|
|
164
|
+
while (inProgress) {
|
|
165
|
+
run = await this.client.beta.threads.runs.retrieve(threadId, runId);
|
|
166
|
+
inProgress = ["in_progress", "queued"].includes(run.status);
|
|
167
|
+
if (inProgress) {
|
|
168
|
+
await (0, time_js_1.sleep)(this.pollIntervalMs);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return run;
|
|
172
|
+
}
|
|
173
|
+
async _getResponse(runId, threadId) {
|
|
174
|
+
const run = await this._waitForRun(runId, threadId);
|
|
175
|
+
if (run.status === "completed") {
|
|
176
|
+
const messages = await this.client.beta.threads.messages.list(threadId, {
|
|
177
|
+
order: "asc",
|
|
178
|
+
});
|
|
179
|
+
const newMessages = messages.data.filter((msg) => msg.run_id === runId);
|
|
180
|
+
if (!this.asAgent) {
|
|
181
|
+
return newMessages;
|
|
182
|
+
}
|
|
183
|
+
const answer = newMessages.flatMap((msg) => msg.content);
|
|
184
|
+
if (answer.every((item) => item.type === "text")) {
|
|
185
|
+
const answerString = answer
|
|
186
|
+
.map((item) => item.type === "text" && item.text.value)
|
|
187
|
+
.join("\n");
|
|
188
|
+
return {
|
|
189
|
+
returnValues: {
|
|
190
|
+
output: answerString,
|
|
191
|
+
},
|
|
192
|
+
log: "",
|
|
193
|
+
runId,
|
|
194
|
+
threadId,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
else if (run.status === "requires_action") {
|
|
199
|
+
if (!this.asAgent) {
|
|
200
|
+
return run.required_action?.submit_tool_outputs.tool_calls ?? [];
|
|
201
|
+
}
|
|
202
|
+
const actions = [];
|
|
203
|
+
run.required_action?.submit_tool_outputs.tool_calls.forEach((item) => {
|
|
204
|
+
const functionCall = item.function;
|
|
205
|
+
const args = JSON.parse(functionCall.arguments);
|
|
206
|
+
actions.push({
|
|
207
|
+
tool: functionCall.name,
|
|
208
|
+
toolInput: args,
|
|
209
|
+
toolCallId: item.id,
|
|
210
|
+
log: "",
|
|
211
|
+
runId,
|
|
212
|
+
threadId,
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
return actions;
|
|
216
|
+
}
|
|
217
|
+
const runInfo = JSON.stringify(run, null, 2);
|
|
218
|
+
throw new Error(`Unexpected run status ${run.status}.\nFull run info:\n\n${runInfo}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
exports.OpenAIAssistantRunnable = OpenAIAssistantRunnable;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type ClientOptions, OpenAI as OpenAIClient } from "openai";
|
|
2
|
+
import { Runnable } from "../../schema/runnable/base.js";
|
|
3
|
+
import type { RunnableConfig } from "../../schema/runnable/config.js";
|
|
4
|
+
import type { OpenAIAssistantFinish, OpenAIAssistantAction, OpenAIToolType } from "./schema.js";
|
|
5
|
+
import { StructuredTool } from "../../tools/base.js";
|
|
6
|
+
type ThreadMessage = OpenAIClient.Beta.Threads.ThreadMessage;
|
|
7
|
+
type RequiredActionFunctionToolCall = OpenAIClient.Beta.Threads.RequiredActionFunctionToolCall;
|
|
8
|
+
type ExtractRunOutput<AsAgent extends boolean | undefined> = AsAgent extends true ? OpenAIAssistantFinish | OpenAIAssistantAction[] : ThreadMessage[] | RequiredActionFunctionToolCall[];
|
|
9
|
+
export type OpenAIAssistantRunnableInput<AsAgent extends boolean | undefined = undefined> = {
|
|
10
|
+
client?: OpenAIClient;
|
|
11
|
+
clientOptions?: ClientOptions;
|
|
12
|
+
assistantId: string;
|
|
13
|
+
pollIntervalMs?: number;
|
|
14
|
+
asAgent?: AsAgent;
|
|
15
|
+
};
|
|
16
|
+
export declare class OpenAIAssistantRunnable<AsAgent extends boolean | undefined, RunInput extends Record<string, any> = Record<string, any>> extends Runnable<RunInput, ExtractRunOutput<AsAgent>> {
|
|
17
|
+
lc_namespace: string[];
|
|
18
|
+
private client;
|
|
19
|
+
assistantId: string;
|
|
20
|
+
pollIntervalMs: number;
|
|
21
|
+
asAgent?: AsAgent;
|
|
22
|
+
constructor(fields: OpenAIAssistantRunnableInput<AsAgent>);
|
|
23
|
+
static createAssistant<AsAgent extends boolean>({ model, name, instructions, tools, client, clientOptions, asAgent, pollIntervalMs, }: Omit<OpenAIAssistantRunnableInput<AsAgent>, "assistantId"> & {
|
|
24
|
+
model: string;
|
|
25
|
+
name?: string;
|
|
26
|
+
instructions?: string;
|
|
27
|
+
tools?: OpenAIToolType | Array<StructuredTool>;
|
|
28
|
+
}): Promise<OpenAIAssistantRunnable<AsAgent, Record<string, any>>>;
|
|
29
|
+
invoke(input: RunInput, _options?: RunnableConfig): Promise<ExtractRunOutput<AsAgent>>;
|
|
30
|
+
private _parseStepsInput;
|
|
31
|
+
private _createRun;
|
|
32
|
+
private _createThreadAndRun;
|
|
33
|
+
private _waitForRun;
|
|
34
|
+
private _getResponse;
|
|
35
|
+
}
|
|
36
|
+
export {};
|