@langchain/core 0.2.18 → 0.2.19
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/callbacks/manager.cjs +94 -19
- package/dist/callbacks/manager.d.ts +3 -1
- package/dist/callbacks/manager.js +94 -19
- package/dist/messages/base.cjs +16 -1
- package/dist/messages/base.d.ts +9 -0
- package/dist/messages/base.js +14 -0
- package/dist/messages/tool.cjs +23 -0
- package/dist/messages/tool.d.ts +15 -0
- package/dist/messages/tool.js +24 -1
- package/dist/messages/utils.cjs +1 -1
- package/dist/messages/utils.js +1 -1
- package/dist/output_parsers/string.cjs +1 -0
- package/dist/output_parsers/string.js +1 -0
- package/dist/runnables/base.cjs +1 -3
- package/dist/runnables/base.js +1 -3
- package/dist/runnables/remote.cjs +3 -1
- package/dist/runnables/remote.js +3 -1
- package/dist/tools/index.cjs +15 -6
- package/dist/tools/index.d.ts +21 -12
- package/dist/tools/index.js +15 -6
- package/dist/utils/testing/index.cjs +161 -3
- package/dist/utils/testing/index.d.ts +94 -3
- package/dist/utils/testing/index.js +160 -3
- package/package.json +4 -3
- package/dist/caches/tests/in_memory_cache.test.d.ts +0 -1
- package/dist/caches/tests/in_memory_cache.test.js +0 -33
- package/dist/callbacks/tests/callbacks.test.d.ts +0 -1
- package/dist/callbacks/tests/callbacks.test.js +0 -495
- package/dist/callbacks/tests/manager.int.test.d.ts +0 -1
- package/dist/callbacks/tests/manager.int.test.js +0 -29
- package/dist/callbacks/tests/run_collector.test.d.ts +0 -1
- package/dist/callbacks/tests/run_collector.test.js +0 -58
- package/dist/language_models/tests/chat_models.test.d.ts +0 -1
- package/dist/language_models/tests/chat_models.test.js +0 -204
- package/dist/language_models/tests/count_tokens.test.d.ts +0 -1
- package/dist/language_models/tests/count_tokens.test.js +0 -19
- package/dist/language_models/tests/llms.test.d.ts +0 -1
- package/dist/language_models/tests/llms.test.js +0 -52
- package/dist/messages/tests/base_message.test.d.ts +0 -1
- package/dist/messages/tests/base_message.test.js +0 -245
- package/dist/messages/tests/message_utils.test.d.ts +0 -1
- package/dist/messages/tests/message_utils.test.js +0 -434
- package/dist/output_parsers/openai_tools/tests/json_output_tools_parser.test.d.ts +0 -1
- package/dist/output_parsers/openai_tools/tests/json_output_tools_parser.test.js +0 -81
- package/dist/output_parsers/tests/json.test.d.ts +0 -1
- package/dist/output_parsers/tests/json.test.js +0 -427
- package/dist/output_parsers/tests/output_parser.test.d.ts +0 -1
- package/dist/output_parsers/tests/output_parser.test.js +0 -78
- package/dist/output_parsers/tests/string.test.d.ts +0 -1
- package/dist/output_parsers/tests/string.test.js +0 -68
- package/dist/output_parsers/tests/structured.test.d.ts +0 -1
- package/dist/output_parsers/tests/structured.test.js +0 -166
- package/dist/output_parsers/tests/xml.test.d.ts +0 -1
- package/dist/output_parsers/tests/xml.test.js +0 -81
- package/dist/prompts/tests/chat.mustache.test.d.ts +0 -1
- package/dist/prompts/tests/chat.mustache.test.js +0 -129
- package/dist/prompts/tests/chat.test.d.ts +0 -1
- package/dist/prompts/tests/chat.test.js +0 -557
- package/dist/prompts/tests/few_shot.test.d.ts +0 -1
- package/dist/prompts/tests/few_shot.test.js +0 -224
- package/dist/prompts/tests/pipeline.test.d.ts +0 -1
- package/dist/prompts/tests/pipeline.test.js +0 -101
- package/dist/prompts/tests/prompt.mustache.test.d.ts +0 -1
- package/dist/prompts/tests/prompt.mustache.test.js +0 -105
- package/dist/prompts/tests/prompt.test.d.ts +0 -1
- package/dist/prompts/tests/prompt.test.js +0 -78
- package/dist/prompts/tests/structured.test.d.ts +0 -1
- package/dist/prompts/tests/structured.test.js +0 -37
- package/dist/prompts/tests/template.test.d.ts +0 -1
- package/dist/prompts/tests/template.test.js +0 -24
- package/dist/runnables/tests/runnable.test.d.ts +0 -1
- package/dist/runnables/tests/runnable.test.js +0 -491
- package/dist/runnables/tests/runnable_binding.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_binding.test.js +0 -46
- package/dist/runnables/tests/runnable_branch.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_branch.test.js +0 -116
- package/dist/runnables/tests/runnable_graph.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_graph.test.js +0 -100
- package/dist/runnables/tests/runnable_history.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_history.test.js +0 -177
- package/dist/runnables/tests/runnable_interface.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_interface.test.js +0 -209
- package/dist/runnables/tests/runnable_map.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_map.test.js +0 -238
- package/dist/runnables/tests/runnable_passthrough.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_passthrough.test.js +0 -96
- package/dist/runnables/tests/runnable_remote.int.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_remote.int.test.js +0 -138
- package/dist/runnables/tests/runnable_remote.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_remote.test.js +0 -200
- package/dist/runnables/tests/runnable_retry.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_retry.test.js +0 -125
- package/dist/runnables/tests/runnable_stream_events.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_stream_events.test.js +0 -1013
- package/dist/runnables/tests/runnable_stream_events_v2.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_stream_events_v2.test.js +0 -2022
- package/dist/runnables/tests/runnable_stream_log.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_stream_log.test.js +0 -71
- package/dist/runnables/tests/runnable_tools.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_tools.test.js +0 -149
- package/dist/runnables/tests/runnable_tracing.int.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_tracing.int.test.js +0 -37
- package/dist/runnables/tests/runnable_with_fallbacks.test.d.ts +0 -1
- package/dist/runnables/tests/runnable_with_fallbacks.test.js +0 -36
- package/dist/singletons/tests/async_local_storage.test.d.ts +0 -1
- package/dist/singletons/tests/async_local_storage.test.js +0 -153
- package/dist/structured_query/tests/utils.test.d.ts +0 -1
- package/dist/structured_query/tests/utils.test.js +0 -47
- package/dist/tools/tests/tools.test.d.ts +0 -1
- package/dist/tools/tests/tools.test.js +0 -85
- package/dist/tracers/tests/langchain_tracer.int.test.d.ts +0 -1
- package/dist/tracers/tests/langchain_tracer.int.test.js +0 -74
- package/dist/tracers/tests/langsmith_interop.test.d.ts +0 -1
- package/dist/tracers/tests/langsmith_interop.test.js +0 -551
- package/dist/tracers/tests/tracer.test.d.ts +0 -1
- package/dist/tracers/tests/tracer.test.js +0 -378
- package/dist/utils/testing/tests/chatfake.test.d.ts +0 -1
- package/dist/utils/testing/tests/chatfake.test.js +0 -112
- package/dist/utils/tests/async_caller.test.d.ts +0 -1
- package/dist/utils/tests/async_caller.test.js +0 -27
- package/dist/utils/tests/enviroment.test.d.ts +0 -1
- package/dist/utils/tests/enviroment.test.js +0 -6
- package/dist/utils/tests/function_calling.test.d.ts +0 -1
- package/dist/utils/tests/function_calling.test.js +0 -107
- package/dist/utils/tests/math_utils.test.d.ts +0 -1
- package/dist/utils/tests/math_utils.test.js +0 -139
- package/dist/utils/tests/polyfill_stream.test.d.ts +0 -1
- package/dist/utils/tests/polyfill_stream.test.js +0 -15
|
@@ -1,491 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-promise-executor-return */
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
4
|
-
import { v4 as uuidv4 } from "uuid";
|
|
5
|
-
import { jest } from "@jest/globals";
|
|
6
|
-
import { createChatMessageChunkEncoderStream } from "../../language_models/chat_models.js";
|
|
7
|
-
import { HumanMessage } from "../../messages/index.js";
|
|
8
|
-
import { OutputParserException } from "../../output_parsers/base.js";
|
|
9
|
-
import { StringOutputParser } from "../../output_parsers/string.js";
|
|
10
|
-
import { ChatPromptTemplate, SystemMessagePromptTemplate, } from "../../prompts/chat.js";
|
|
11
|
-
import { PromptTemplate } from "../../prompts/prompt.js";
|
|
12
|
-
import { FakeLLM, FakeChatModel, FakeStreamingLLM, FakeSplitIntoListParser, FakeRunnable, FakeListChatModel, SingleRunExtractor, FakeStreamingChatModel, } from "../../utils/testing/index.js";
|
|
13
|
-
import { RunnableSequence, RunnableLambda } from "../base.js";
|
|
14
|
-
import { RouterRunnable } from "../router.js";
|
|
15
|
-
import { JsonOutputParser } from "../../output_parsers/json.js";
|
|
16
|
-
test("Test batch", async () => {
|
|
17
|
-
const llm = new FakeLLM({});
|
|
18
|
-
const results = await llm.batch(["Hi there!", "Hey hey"]);
|
|
19
|
-
expect(results.length).toBe(2);
|
|
20
|
-
});
|
|
21
|
-
test("Test stream", async () => {
|
|
22
|
-
const llm = new FakeLLM({});
|
|
23
|
-
const stream = await llm.stream("Hi there!");
|
|
24
|
-
const reader = stream
|
|
25
|
-
.pipeThrough(new TextEncoderStream())
|
|
26
|
-
.pipeThrough(new TextDecoderStream())
|
|
27
|
-
.getReader();
|
|
28
|
-
let done = false;
|
|
29
|
-
while (!done) {
|
|
30
|
-
const chunk = await reader.read();
|
|
31
|
-
done = chunk.done;
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
test("Test stream with an immediate thrown error", async () => {
|
|
35
|
-
const llm = new FakeStreamingLLM({
|
|
36
|
-
thrownErrorString: "testing",
|
|
37
|
-
});
|
|
38
|
-
try {
|
|
39
|
-
await llm.stream("Hi there!");
|
|
40
|
-
}
|
|
41
|
-
catch (e) {
|
|
42
|
-
expect(e.message).toEqual("testing");
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
test("Test chat model stream", async () => {
|
|
46
|
-
const llm = new FakeChatModel({});
|
|
47
|
-
const stream = await llm.stream("Hi there!");
|
|
48
|
-
const reader = stream
|
|
49
|
-
.pipeThrough(createChatMessageChunkEncoderStream())
|
|
50
|
-
.pipeThrough(new TextDecoderStream())
|
|
51
|
-
.getReader();
|
|
52
|
-
let done = false;
|
|
53
|
-
while (!done) {
|
|
54
|
-
const chunk = await reader.read();
|
|
55
|
-
console.log(chunk);
|
|
56
|
-
done = chunk.done;
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
test("Pipe from one runnable to the next", async () => {
|
|
60
|
-
const promptTemplate = PromptTemplate.fromTemplate("{input}");
|
|
61
|
-
const llm = new FakeLLM({});
|
|
62
|
-
const runnable = promptTemplate.pipe(llm);
|
|
63
|
-
const result = await runnable.invoke({ input: "Hello world!" });
|
|
64
|
-
console.log(result);
|
|
65
|
-
expect(result).toBe("Hello world!");
|
|
66
|
-
});
|
|
67
|
-
test("Stream the entire way through", async () => {
|
|
68
|
-
const llm = new FakeStreamingLLM({});
|
|
69
|
-
const stream = await llm.pipe(new StringOutputParser()).stream("Hi there!");
|
|
70
|
-
const chunks = [];
|
|
71
|
-
for await (const chunk of stream) {
|
|
72
|
-
chunks.push(chunk);
|
|
73
|
-
console.log(chunk);
|
|
74
|
-
}
|
|
75
|
-
expect(chunks.length).toEqual("Hi there!".length);
|
|
76
|
-
expect(chunks.join("")).toEqual("Hi there!");
|
|
77
|
-
});
|
|
78
|
-
test("Callback order with transform streaming", async () => {
|
|
79
|
-
const prompt = ChatPromptTemplate.fromTemplate(`{input}`);
|
|
80
|
-
const llm = new FakeStreamingLLM({});
|
|
81
|
-
const order = [];
|
|
82
|
-
const stream = await prompt
|
|
83
|
-
.pipe(llm)
|
|
84
|
-
.pipe(new StringOutputParser())
|
|
85
|
-
.stream({ input: "Hi there!" }, {
|
|
86
|
-
callbacks: [
|
|
87
|
-
{
|
|
88
|
-
handleChainStart: (chain) => order.push(chain.id[chain.id.length - 1]),
|
|
89
|
-
handleLLMStart: (llm) => order.push(llm.id[llm.id.length - 1]),
|
|
90
|
-
},
|
|
91
|
-
],
|
|
92
|
-
});
|
|
93
|
-
const chunks = [];
|
|
94
|
-
for await (const chunk of stream) {
|
|
95
|
-
chunks.push(chunk);
|
|
96
|
-
console.log(chunk);
|
|
97
|
-
}
|
|
98
|
-
expect(order).toEqual([
|
|
99
|
-
"RunnableSequence",
|
|
100
|
-
"ChatPromptTemplate",
|
|
101
|
-
"FakeStreamingLLM",
|
|
102
|
-
"StrOutputParser",
|
|
103
|
-
]);
|
|
104
|
-
expect(chunks.length).toEqual("Human: Hi there!".length);
|
|
105
|
-
expect(chunks.join("")).toEqual("Human: Hi there!");
|
|
106
|
-
});
|
|
107
|
-
test("Don't use intermediate streaming", async () => {
|
|
108
|
-
const llm = new FakeStreamingLLM({});
|
|
109
|
-
const stream = await llm
|
|
110
|
-
.pipe(new StringOutputParser())
|
|
111
|
-
.pipe(new FakeLLM({}))
|
|
112
|
-
.stream("Hi there!");
|
|
113
|
-
const chunks = [];
|
|
114
|
-
for await (const chunk of stream) {
|
|
115
|
-
chunks.push(chunk);
|
|
116
|
-
console.log(chunk);
|
|
117
|
-
}
|
|
118
|
-
expect(chunks.length).toEqual(1);
|
|
119
|
-
expect(chunks[0]).toEqual("Hi there!");
|
|
120
|
-
});
|
|
121
|
-
test("Router runnables", async () => {
|
|
122
|
-
const mathLLM = new FakeLLM({});
|
|
123
|
-
mathLLM.response = "I am a math genius!";
|
|
124
|
-
const chain1 = PromptTemplate.fromTemplate("You are a math genius. Answer the question: {question}").pipe(mathLLM);
|
|
125
|
-
const englishLLM = new FakeLLM({});
|
|
126
|
-
englishLLM.response = "I am an English genius!";
|
|
127
|
-
const chain2 = PromptTemplate.fromTemplate("You are an english major. Answer the question: {question}").pipe(englishLLM);
|
|
128
|
-
const router = new RouterRunnable({
|
|
129
|
-
runnables: { math: chain1, english: chain2 },
|
|
130
|
-
});
|
|
131
|
-
const chain = RunnableSequence.from([
|
|
132
|
-
{
|
|
133
|
-
key: (x) => x.key,
|
|
134
|
-
input: { question: (x) => x.question },
|
|
135
|
-
},
|
|
136
|
-
router,
|
|
137
|
-
]);
|
|
138
|
-
const result = await chain.invoke({ key: "math", question: "2 + 2" });
|
|
139
|
-
expect(result).toEqual("I am a math genius!");
|
|
140
|
-
const result2 = await chain.batch([
|
|
141
|
-
{
|
|
142
|
-
key: "math",
|
|
143
|
-
question: "2 + 2",
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
key: "english",
|
|
147
|
-
question: "2 + 2",
|
|
148
|
-
},
|
|
149
|
-
]);
|
|
150
|
-
expect(result2).toEqual(["I am a math genius!", "I am an English genius!"]);
|
|
151
|
-
});
|
|
152
|
-
test("RunnableLambda that returns a runnable should invoke the runnable", async () => {
|
|
153
|
-
const runnable = new RunnableLambda({
|
|
154
|
-
func: () => new RunnableLambda({
|
|
155
|
-
func: () => "testing",
|
|
156
|
-
}),
|
|
157
|
-
});
|
|
158
|
-
const result = await runnable.invoke({});
|
|
159
|
-
expect(result).toEqual("testing");
|
|
160
|
-
});
|
|
161
|
-
test("RunnableLambda that returns an async iterator should consume it", async () => {
|
|
162
|
-
const runnable = new RunnableLambda({
|
|
163
|
-
async *func() {
|
|
164
|
-
yield "test";
|
|
165
|
-
yield "ing";
|
|
166
|
-
},
|
|
167
|
-
});
|
|
168
|
-
const result = await runnable.invoke({});
|
|
169
|
-
expect(result).toEqual("testing");
|
|
170
|
-
const chunks = [];
|
|
171
|
-
const stream = await runnable.stream({});
|
|
172
|
-
for await (const chunk of stream) {
|
|
173
|
-
chunks.push(chunk);
|
|
174
|
-
}
|
|
175
|
-
expect(chunks).toEqual(["test", "ing"]);
|
|
176
|
-
});
|
|
177
|
-
test("RunnableLambda that returns an async iterable should consume it", async () => {
|
|
178
|
-
const runnable = new RunnableLambda({
|
|
179
|
-
func() {
|
|
180
|
-
return new ReadableStream({
|
|
181
|
-
async start(controller) {
|
|
182
|
-
controller.enqueue("test");
|
|
183
|
-
controller.enqueue("ing");
|
|
184
|
-
controller.close();
|
|
185
|
-
},
|
|
186
|
-
});
|
|
187
|
-
},
|
|
188
|
-
});
|
|
189
|
-
const result = await runnable.invoke({});
|
|
190
|
-
expect(result).toEqual("testing");
|
|
191
|
-
const chunks = [];
|
|
192
|
-
const stream = await runnable.stream({});
|
|
193
|
-
for await (const chunk of stream) {
|
|
194
|
-
chunks.push(chunk);
|
|
195
|
-
}
|
|
196
|
-
expect(chunks).toEqual(["test", "ing"]);
|
|
197
|
-
});
|
|
198
|
-
test("RunnableLambda that returns a promise for async iterable should consume it", async () => {
|
|
199
|
-
const runnable = new RunnableLambda({
|
|
200
|
-
async func() {
|
|
201
|
-
return new ReadableStream({
|
|
202
|
-
async start(controller) {
|
|
203
|
-
controller.enqueue("test");
|
|
204
|
-
controller.enqueue("ing");
|
|
205
|
-
controller.close();
|
|
206
|
-
},
|
|
207
|
-
});
|
|
208
|
-
},
|
|
209
|
-
});
|
|
210
|
-
const result = await runnable.invoke({});
|
|
211
|
-
expect(result).toEqual("testing");
|
|
212
|
-
const chunks = [];
|
|
213
|
-
const stream = await runnable.stream({});
|
|
214
|
-
for await (const chunk of stream) {
|
|
215
|
-
chunks.push(chunk);
|
|
216
|
-
}
|
|
217
|
-
expect(chunks).toEqual(["test", "ing"]);
|
|
218
|
-
});
|
|
219
|
-
test("RunnableLambda that returns an iterator should consume it", async () => {
|
|
220
|
-
const runnable = new RunnableLambda({
|
|
221
|
-
*func() {
|
|
222
|
-
yield "test";
|
|
223
|
-
yield "ing";
|
|
224
|
-
},
|
|
225
|
-
});
|
|
226
|
-
const result = await runnable.invoke({});
|
|
227
|
-
expect(result).toEqual("testing");
|
|
228
|
-
const chunks = [];
|
|
229
|
-
const stream = await runnable.stream({});
|
|
230
|
-
for await (const chunk of stream) {
|
|
231
|
-
chunks.push(chunk);
|
|
232
|
-
}
|
|
233
|
-
expect(chunks).toEqual(["test", "ing"]);
|
|
234
|
-
});
|
|
235
|
-
test("RunnableLambda that returns a streaming runnable should stream output from the inner runnable", async () => {
|
|
236
|
-
const runnable = new RunnableLambda({
|
|
237
|
-
func: () => new FakeStreamingLLM({}),
|
|
238
|
-
});
|
|
239
|
-
const stream = await runnable.stream("hello");
|
|
240
|
-
const chunks = [];
|
|
241
|
-
for await (const chunk of stream) {
|
|
242
|
-
chunks.push(chunk);
|
|
243
|
-
}
|
|
244
|
-
expect(chunks).toEqual(["h", "e", "l", "l", "o"]);
|
|
245
|
-
});
|
|
246
|
-
test("RunnableEach", async () => {
|
|
247
|
-
const parser = new FakeSplitIntoListParser();
|
|
248
|
-
expect(await parser.invoke("first item, second item")).toEqual([
|
|
249
|
-
"first item",
|
|
250
|
-
"second item",
|
|
251
|
-
]);
|
|
252
|
-
expect(await parser.map().invoke(["a, b", "c"])).toEqual([["a", "b"], ["c"]]);
|
|
253
|
-
expect(await parser
|
|
254
|
-
.map()
|
|
255
|
-
.map()
|
|
256
|
-
.invoke([["a, b", "c"], ["c, e"]])).toEqual([[["a", "b"], ["c"]], [["c", "e"]]]);
|
|
257
|
-
});
|
|
258
|
-
test("Runnable withConfig", async () => {
|
|
259
|
-
const fake = new FakeRunnable({
|
|
260
|
-
returnOptions: true,
|
|
261
|
-
});
|
|
262
|
-
const result = await fake.withConfig({ tags: ["a-tag"] }).invoke("hello");
|
|
263
|
-
expect(result.tags).toEqual(["a-tag"]);
|
|
264
|
-
const stream = await fake
|
|
265
|
-
.withConfig({
|
|
266
|
-
metadata: {
|
|
267
|
-
a: "b",
|
|
268
|
-
b: "c",
|
|
269
|
-
},
|
|
270
|
-
tags: ["a-tag"],
|
|
271
|
-
})
|
|
272
|
-
.stream("hi", { tags: ["b-tag"], metadata: { a: "updated" } });
|
|
273
|
-
const chunks = [];
|
|
274
|
-
for await (const chunk of stream) {
|
|
275
|
-
chunks.push(chunk);
|
|
276
|
-
}
|
|
277
|
-
expect(chunks.length).toEqual(1);
|
|
278
|
-
expect(chunks[0]?.tags).toEqual(["a-tag", "b-tag"]);
|
|
279
|
-
expect(chunks[0]?.metadata).toEqual({ a: "updated", b: "c" });
|
|
280
|
-
});
|
|
281
|
-
test("Listeners work", async () => {
|
|
282
|
-
const prompt = ChatPromptTemplate.fromMessages([
|
|
283
|
-
SystemMessagePromptTemplate.fromTemplate("You are a nice assistant."),
|
|
284
|
-
["human", "{question}"],
|
|
285
|
-
]);
|
|
286
|
-
const model = new FakeListChatModel({
|
|
287
|
-
responses: ["foo"],
|
|
288
|
-
});
|
|
289
|
-
const chain = prompt.pipe(model);
|
|
290
|
-
const mockStart = jest.fn();
|
|
291
|
-
const mockEnd = jest.fn();
|
|
292
|
-
await chain
|
|
293
|
-
.withListeners({
|
|
294
|
-
onStart: (run) => {
|
|
295
|
-
mockStart(run);
|
|
296
|
-
},
|
|
297
|
-
onEnd: (run) => {
|
|
298
|
-
mockEnd(run);
|
|
299
|
-
},
|
|
300
|
-
})
|
|
301
|
-
.invoke({ question: "What is the meaning of life?" });
|
|
302
|
-
expect(mockStart).toHaveBeenCalledTimes(1);
|
|
303
|
-
expect(mockStart.mock.calls[0][0].name).toBe("RunnableSequence");
|
|
304
|
-
expect(mockEnd).toHaveBeenCalledTimes(1);
|
|
305
|
-
});
|
|
306
|
-
test("Listeners work with async handlers", async () => {
|
|
307
|
-
const prompt = ChatPromptTemplate.fromMessages([
|
|
308
|
-
SystemMessagePromptTemplate.fromTemplate("You are a nice assistant."),
|
|
309
|
-
["human", "{question}"],
|
|
310
|
-
]);
|
|
311
|
-
const model = new FakeListChatModel({
|
|
312
|
-
responses: ["foo"],
|
|
313
|
-
});
|
|
314
|
-
const chain = prompt.pipe(model);
|
|
315
|
-
const mockStart = jest.fn();
|
|
316
|
-
const mockEnd = jest.fn();
|
|
317
|
-
await chain
|
|
318
|
-
.withListeners({
|
|
319
|
-
onStart: async (run) => {
|
|
320
|
-
const promise = new Promise((resolve) => setTimeout(resolve, 2000));
|
|
321
|
-
await promise;
|
|
322
|
-
mockStart(run);
|
|
323
|
-
},
|
|
324
|
-
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
325
|
-
onEnd: async (run) => {
|
|
326
|
-
const promise = new Promise((resolve) => setTimeout(resolve, 2000));
|
|
327
|
-
await promise;
|
|
328
|
-
mockEnd(run);
|
|
329
|
-
},
|
|
330
|
-
})
|
|
331
|
-
.invoke({ question: "What is the meaning of life?" });
|
|
332
|
-
expect(mockStart).toHaveBeenCalledTimes(1);
|
|
333
|
-
expect(mockStart.mock.calls[0][0].name).toBe("RunnableSequence");
|
|
334
|
-
expect(mockEnd).toHaveBeenCalledTimes(1);
|
|
335
|
-
});
|
|
336
|
-
test("Create a runnable sequence and run it", async () => {
|
|
337
|
-
const promptTemplate = PromptTemplate.fromTemplate("{input}");
|
|
338
|
-
const llm = new FakeChatModel({});
|
|
339
|
-
const parser = new StringOutputParser();
|
|
340
|
-
const text = `Jello world`;
|
|
341
|
-
const runnable = promptTemplate.pipe(llm).pipe(parser);
|
|
342
|
-
const result = await runnable.invoke({ input: text });
|
|
343
|
-
console.log(result);
|
|
344
|
-
expect(result).toEqual("Jello world");
|
|
345
|
-
});
|
|
346
|
-
test("Create a runnable sequence with a static method with invalid output and catch the error", async () => {
|
|
347
|
-
const promptTemplate = PromptTemplate.fromTemplate("{input}");
|
|
348
|
-
const llm = new FakeChatModel({});
|
|
349
|
-
const parser = (input) => {
|
|
350
|
-
console.log(input);
|
|
351
|
-
try {
|
|
352
|
-
const parsedInput = typeof input.content === "string"
|
|
353
|
-
? JSON.parse(input.content)
|
|
354
|
-
: input.content;
|
|
355
|
-
if (!("outputValue" in parsedInput) ||
|
|
356
|
-
parsedInput.outputValue !== "Hello sequence!") {
|
|
357
|
-
throw new Error("Test failed!");
|
|
358
|
-
}
|
|
359
|
-
else {
|
|
360
|
-
return input;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
catch (e) {
|
|
364
|
-
throw new OutputParserException("Invalid output");
|
|
365
|
-
}
|
|
366
|
-
};
|
|
367
|
-
const runnable = RunnableSequence.from([promptTemplate, llm, parser]);
|
|
368
|
-
await expect(async () => {
|
|
369
|
-
const result = await runnable.invoke({ input: "Hello sequence!" });
|
|
370
|
-
console.log(result);
|
|
371
|
-
}).rejects.toThrow(OutputParserException);
|
|
372
|
-
});
|
|
373
|
-
test("RunnableSequence can pass config to every step in batched request", async () => {
|
|
374
|
-
let numSeen = 0;
|
|
375
|
-
const addOne = (x, options) => {
|
|
376
|
-
if (options?.configurable?.isPresent === true) {
|
|
377
|
-
numSeen += 1;
|
|
378
|
-
}
|
|
379
|
-
return x + 1;
|
|
380
|
-
};
|
|
381
|
-
const addTwo = (x, options) => {
|
|
382
|
-
if (options?.configurable?.isPresent === true) {
|
|
383
|
-
numSeen += 1;
|
|
384
|
-
}
|
|
385
|
-
return x + 2;
|
|
386
|
-
};
|
|
387
|
-
const addThree = (x, options) => {
|
|
388
|
-
if (options?.configurable?.isPresent === true) {
|
|
389
|
-
numSeen += 1;
|
|
390
|
-
}
|
|
391
|
-
return x + 3;
|
|
392
|
-
};
|
|
393
|
-
const sequence = RunnableSequence.from([addOne, addTwo, addThree]);
|
|
394
|
-
await sequence.batch([1], {
|
|
395
|
-
configurable: {
|
|
396
|
-
isPresent: true,
|
|
397
|
-
},
|
|
398
|
-
});
|
|
399
|
-
expect(numSeen).toBe(3);
|
|
400
|
-
});
|
|
401
|
-
test("Should aggregate properly", async () => {
|
|
402
|
-
const model = new FakeStreamingLLM({
|
|
403
|
-
responses: [
|
|
404
|
-
`{"countries": [{"name": "France", "population": 67391582}, {"name": "Spain", "population": 46754778}, {"name": "Japan", "population": 126476461}]}`,
|
|
405
|
-
],
|
|
406
|
-
});
|
|
407
|
-
// A function that does not operates on input streams and breaks streaming.
|
|
408
|
-
const extractCountryNames = (inputs) => {
|
|
409
|
-
if (!Array.isArray(inputs.countries)) {
|
|
410
|
-
return "";
|
|
411
|
-
}
|
|
412
|
-
return inputs.countries.map((country) => country.name);
|
|
413
|
-
};
|
|
414
|
-
const chain = model.pipe(new JsonOutputParser()).pipe(extractCountryNames);
|
|
415
|
-
const stream = await chain.stream(`output a list of the countries france, spain and japan and their populations in JSON format. Use a dict with an outer key of "countries" which contains a list of countries. Each country should have the key "name" and "population"`);
|
|
416
|
-
const chunks = [];
|
|
417
|
-
for await (const chunk of stream) {
|
|
418
|
-
chunks.push(chunk);
|
|
419
|
-
}
|
|
420
|
-
expect(chunks.length).toEqual(1);
|
|
421
|
-
expect(chunks[0]).toEqual(["France", "Spain", "Japan"]);
|
|
422
|
-
});
|
|
423
|
-
describe("runId config", () => {
|
|
424
|
-
test("invoke", async () => {
|
|
425
|
-
const tracer = new SingleRunExtractor();
|
|
426
|
-
const llm = new FakeChatModel({});
|
|
427
|
-
const testId = uuidv4();
|
|
428
|
-
await llm.invoke("gg", {
|
|
429
|
-
callbacks: [tracer],
|
|
430
|
-
runId: testId,
|
|
431
|
-
});
|
|
432
|
-
const run = await tracer.extract();
|
|
433
|
-
expect(run.id).toBe(testId);
|
|
434
|
-
});
|
|
435
|
-
test("batch", async () => {
|
|
436
|
-
jest.spyOn(console, "warn").mockImplementation(() => { });
|
|
437
|
-
const tracer = new SingleRunExtractor();
|
|
438
|
-
const llm = new FakeChatModel({});
|
|
439
|
-
const message = new HumanMessage("hello world");
|
|
440
|
-
const testId = uuidv4();
|
|
441
|
-
const res = await llm.batch([[message], [message]], {
|
|
442
|
-
callbacks: [tracer],
|
|
443
|
-
runId: testId,
|
|
444
|
-
});
|
|
445
|
-
const run = await tracer.extract();
|
|
446
|
-
expect(run.id).toBe(testId);
|
|
447
|
-
expect(res.length).toBe(2);
|
|
448
|
-
// .batch will warn if a runId is passed
|
|
449
|
-
// along with multiple messages
|
|
450
|
-
expect(console.warn).toBeCalled();
|
|
451
|
-
});
|
|
452
|
-
test("stream", async () => {
|
|
453
|
-
const tracer = new SingleRunExtractor();
|
|
454
|
-
const llm = new FakeStreamingChatModel({});
|
|
455
|
-
const testId = uuidv4();
|
|
456
|
-
const stream = await llm.stream("gg", {
|
|
457
|
-
callbacks: [tracer],
|
|
458
|
-
runId: testId,
|
|
459
|
-
});
|
|
460
|
-
for await (const _ of stream) {
|
|
461
|
-
// no-op
|
|
462
|
-
}
|
|
463
|
-
const run = await tracer.extract();
|
|
464
|
-
expect(run.id).toBe(testId);
|
|
465
|
-
});
|
|
466
|
-
test("stream (via llm)", async () => {
|
|
467
|
-
const tracer = new SingleRunExtractor();
|
|
468
|
-
const llm = new FakeStreamingLLM({});
|
|
469
|
-
const testId = uuidv4();
|
|
470
|
-
const stream = await llm.stream("gg", {
|
|
471
|
-
callbacks: [tracer],
|
|
472
|
-
runId: testId,
|
|
473
|
-
});
|
|
474
|
-
for await (const _ of stream) {
|
|
475
|
-
// no-op
|
|
476
|
-
}
|
|
477
|
-
const run = await tracer.extract();
|
|
478
|
-
expect(run.id).toBe(testId);
|
|
479
|
-
});
|
|
480
|
-
test("invoke (via llm)", async () => {
|
|
481
|
-
const tracer = new SingleRunExtractor();
|
|
482
|
-
const llm = new FakeLLM({});
|
|
483
|
-
const testId = uuidv4();
|
|
484
|
-
await llm.invoke("gg", {
|
|
485
|
-
callbacks: [tracer],
|
|
486
|
-
runId: testId,
|
|
487
|
-
});
|
|
488
|
-
const run = await tracer.extract();
|
|
489
|
-
expect(run.id).toBe(testId);
|
|
490
|
-
});
|
|
491
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-promise-executor-return */
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
-
import { test } from "@jest/globals";
|
|
4
|
-
import { StringOutputParser } from "../../output_parsers/string.js";
|
|
5
|
-
import { FakeChatModel, FakeStreamingLLM } from "../../utils/testing/index.js";
|
|
6
|
-
test("Bind kwargs to a runnable", async () => {
|
|
7
|
-
const llm = new FakeChatModel({});
|
|
8
|
-
const result = await llm
|
|
9
|
-
.bind({ stop: ["testing"] })
|
|
10
|
-
.pipe(new StringOutputParser())
|
|
11
|
-
.invoke("Hi there!");
|
|
12
|
-
console.log(result);
|
|
13
|
-
expect(result).toEqual("testing");
|
|
14
|
-
});
|
|
15
|
-
test("Bind kwargs to a runnable with a batch call", async () => {
|
|
16
|
-
const llm = new FakeChatModel({});
|
|
17
|
-
const result = await llm
|
|
18
|
-
.bind({ stop: ["testing"] })
|
|
19
|
-
.pipe(new StringOutputParser())
|
|
20
|
-
.batch(["Hi there!", "hey hey", "Hi there!", "hey hey"]);
|
|
21
|
-
console.log(result);
|
|
22
|
-
expect(result).toEqual(["testing", "testing", "testing", "testing"]);
|
|
23
|
-
});
|
|
24
|
-
test("Stream with RunnableBinding", async () => {
|
|
25
|
-
const llm = new FakeStreamingLLM({}).bind({ stop: ["dummy"] });
|
|
26
|
-
const stream = await llm.pipe(new StringOutputParser()).stream("Hi there!");
|
|
27
|
-
const chunks = [];
|
|
28
|
-
for await (const chunk of stream) {
|
|
29
|
-
chunks.push(chunk);
|
|
30
|
-
console.log(chunk);
|
|
31
|
-
}
|
|
32
|
-
expect(chunks.length).toEqual("Hi there!".length);
|
|
33
|
-
expect(chunks.join("")).toEqual("Hi there!");
|
|
34
|
-
});
|
|
35
|
-
test("Stream through a RunnableBinding if the bound runnable implements transform", async () => {
|
|
36
|
-
const llm = new FakeStreamingLLM({}).bind({ stop: ["dummy"] });
|
|
37
|
-
const outputParser = new StringOutputParser().bind({ callbacks: [] });
|
|
38
|
-
const stream = await llm.pipe(outputParser).stream("Hi there!");
|
|
39
|
-
const chunks = [];
|
|
40
|
-
for await (const chunk of stream) {
|
|
41
|
-
chunks.push(chunk);
|
|
42
|
-
console.log(chunk);
|
|
43
|
-
}
|
|
44
|
-
expect(chunks.length).toEqual("Hi there!".length);
|
|
45
|
-
expect(chunks.join("")).toEqual("Hi there!");
|
|
46
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-promise-executor-return */
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
-
import { test } from "@jest/globals";
|
|
4
|
-
import { RunnableBranch } from "../branch.js";
|
|
5
|
-
import { ChatPromptTemplate } from "../../prompts/chat.js";
|
|
6
|
-
import { FakeStreamingLLM } from "../../utils/testing/index.js";
|
|
7
|
-
import { RunnableSequence } from "../base.js";
|
|
8
|
-
import { StringOutputParser } from "../../output_parsers/string.js";
|
|
9
|
-
test("RunnableBranch invoke", async () => {
|
|
10
|
-
const condition = (x) => x > 0;
|
|
11
|
-
const add = (x) => x + 1;
|
|
12
|
-
const subtract = (x) => x - 1;
|
|
13
|
-
const branch = RunnableBranch.from([
|
|
14
|
-
[condition, add],
|
|
15
|
-
[condition, add],
|
|
16
|
-
subtract,
|
|
17
|
-
]);
|
|
18
|
-
const result = await branch.invoke(1);
|
|
19
|
-
expect(result).toEqual(2);
|
|
20
|
-
const result2 = await branch.invoke(-1);
|
|
21
|
-
expect(result2).toEqual(-2);
|
|
22
|
-
});
|
|
23
|
-
test("RunnableBranch batch", async () => {
|
|
24
|
-
const branch = RunnableBranch.from([
|
|
25
|
-
[(x) => x > 0 && x < 5, (x) => x + 1],
|
|
26
|
-
[(x) => x > 5, (x) => x * 10],
|
|
27
|
-
(x) => x - 1,
|
|
28
|
-
]);
|
|
29
|
-
const batchResult = await branch.batch([1, 10, 0]);
|
|
30
|
-
expect(batchResult).toEqual([2, 100, -1]);
|
|
31
|
-
});
|
|
32
|
-
test("RunnableBranch handles error", async () => {
|
|
33
|
-
let error;
|
|
34
|
-
const branch = RunnableBranch.from([
|
|
35
|
-
[
|
|
36
|
-
(x) => x.startsWith("a"),
|
|
37
|
-
() => {
|
|
38
|
-
throw new Error("Testing");
|
|
39
|
-
},
|
|
40
|
-
],
|
|
41
|
-
(x) => `${x} passed`,
|
|
42
|
-
]);
|
|
43
|
-
const result = await branch.invoke("branch", {
|
|
44
|
-
callbacks: [
|
|
45
|
-
{
|
|
46
|
-
handleChainError: (e) => {
|
|
47
|
-
error = e;
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
],
|
|
51
|
-
});
|
|
52
|
-
// If callbacks are backgrounded
|
|
53
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
54
|
-
expect(result).toBe("branch passed");
|
|
55
|
-
expect(error).toBeUndefined();
|
|
56
|
-
await expect(async () => {
|
|
57
|
-
await branch.invoke("alpha", {
|
|
58
|
-
callbacks: [
|
|
59
|
-
{
|
|
60
|
-
handleChainError: (e) => {
|
|
61
|
-
error = e;
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
});
|
|
66
|
-
}).rejects.toThrow();
|
|
67
|
-
expect(error).toBeDefined();
|
|
68
|
-
});
|
|
69
|
-
test("RunnableBranch invoke", async () => {
|
|
70
|
-
const promptTemplate = ChatPromptTemplate.fromTemplate(`{question}`);
|
|
71
|
-
const model = new FakeStreamingLLM({
|
|
72
|
-
sleep: 1,
|
|
73
|
-
});
|
|
74
|
-
const classificationChain = RunnableSequence.from([
|
|
75
|
-
promptTemplate,
|
|
76
|
-
model,
|
|
77
|
-
new StringOutputParser(),
|
|
78
|
-
]);
|
|
79
|
-
const generalChain = ChatPromptTemplate.fromTemplate(`GENERAL CHAIN`).pipe(model);
|
|
80
|
-
const langChainChain = ChatPromptTemplate.fromTemplate(`LANGCHAIN CHAIN`).pipe(model);
|
|
81
|
-
const branch = RunnableBranch.from([
|
|
82
|
-
[
|
|
83
|
-
(x) => x.topic.toLowerCase().includes("langchain"),
|
|
84
|
-
langChainChain,
|
|
85
|
-
],
|
|
86
|
-
generalChain,
|
|
87
|
-
]);
|
|
88
|
-
const fullChain = RunnableSequence.from([
|
|
89
|
-
{
|
|
90
|
-
topic: classificationChain,
|
|
91
|
-
question: (input) => input.question,
|
|
92
|
-
},
|
|
93
|
-
branch,
|
|
94
|
-
new StringOutputParser(),
|
|
95
|
-
]);
|
|
96
|
-
const stream = await fullChain.stream({
|
|
97
|
-
question: "How do I use langchain? Explain in one sentence",
|
|
98
|
-
});
|
|
99
|
-
const chunks = [];
|
|
100
|
-
for await (const chunk of stream) {
|
|
101
|
-
console.log(chunk);
|
|
102
|
-
chunks.push(chunk);
|
|
103
|
-
}
|
|
104
|
-
expect(chunks.length).toBeGreaterThan(1);
|
|
105
|
-
expect(chunks.join("")).toContain("LANGCHAIN");
|
|
106
|
-
const stream2 = await fullChain.stream({
|
|
107
|
-
question: "What is up? Explain in one sentence",
|
|
108
|
-
});
|
|
109
|
-
const chunks2 = [];
|
|
110
|
-
for await (const chunk of stream2) {
|
|
111
|
-
console.log(chunk);
|
|
112
|
-
chunks2.push(chunk);
|
|
113
|
-
}
|
|
114
|
-
expect(chunks2.length).toBeGreaterThan(1);
|
|
115
|
-
expect(chunks2.join("")).toContain("GENERAL");
|
|
116
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|