@langchain/core 0.2.14 → 0.2.16
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/README.md +1 -1
- package/caches.cjs +1 -1
- package/caches.d.cts +1 -1
- package/caches.d.ts +1 -1
- package/caches.js +1 -1
- package/callbacks/dispatch/web.cjs +1 -0
- package/callbacks/dispatch/web.d.cts +1 -0
- package/callbacks/dispatch/web.d.ts +1 -0
- package/callbacks/dispatch/web.js +1 -0
- package/callbacks/dispatch.cjs +1 -0
- package/callbacks/dispatch.d.cts +1 -0
- package/callbacks/dispatch.d.ts +1 -0
- package/callbacks/dispatch.js +1 -0
- package/dist/{caches.cjs → caches/base.cjs} +6 -6
- package/dist/{caches.d.ts → caches/base.d.ts} +7 -7
- package/dist/{caches.js → caches/base.js} +6 -6
- package/dist/caches/tests/in_memory_cache.test.d.ts +1 -0
- package/dist/caches/tests/in_memory_cache.test.js +33 -0
- package/dist/callbacks/base.cjs +8 -0
- package/dist/callbacks/base.d.ts +16 -10
- package/dist/callbacks/base.js +8 -0
- package/dist/callbacks/dispatch/index.cjs +49 -0
- package/dist/callbacks/dispatch/index.d.ts +35 -0
- package/dist/callbacks/dispatch/index.js +45 -0
- package/dist/callbacks/dispatch/web.cjs +61 -0
- package/dist/callbacks/dispatch/web.d.ts +32 -0
- package/dist/callbacks/dispatch/web.js +57 -0
- package/dist/callbacks/manager.cjs +32 -5
- package/dist/callbacks/manager.d.ts +5 -2
- package/dist/callbacks/manager.js +31 -5
- package/dist/language_models/base.cjs +4 -4
- package/dist/language_models/base.d.ts +2 -2
- package/dist/language_models/base.js +1 -1
- package/dist/language_models/chat_models.d.ts +4 -4
- package/dist/language_models/llms.d.ts +1 -1
- package/dist/language_models/tests/chat_models.test.js +33 -0
- package/dist/load/import_map.cjs +2 -2
- package/dist/load/import_map.d.ts +2 -2
- package/dist/load/import_map.js +2 -2
- package/dist/messages/ai.cjs +2 -0
- package/dist/messages/ai.js +2 -0
- package/dist/messages/base.cjs +45 -5
- package/dist/messages/base.d.ts +1 -0
- package/dist/messages/base.js +43 -4
- package/dist/messages/index.d.ts +1 -1
- package/dist/messages/tests/base_message.test.js +134 -2
- package/dist/messages/tests/message_utils.test.js +54 -2
- package/dist/messages/tool.cjs +31 -0
- package/dist/messages/tool.d.ts +27 -0
- package/dist/messages/tool.js +32 -1
- package/dist/messages/transformers.cjs +1 -0
- package/dist/messages/transformers.js +1 -0
- package/dist/messages/utils.cjs +5 -1
- package/dist/messages/utils.js +5 -1
- package/dist/output_parsers/openai_tools/json_output_tools_parsers.cjs +2 -0
- package/dist/output_parsers/openai_tools/json_output_tools_parsers.js +2 -0
- package/dist/runnables/base.cjs +89 -16
- package/dist/runnables/base.d.ts +51 -0
- package/dist/runnables/base.js +86 -15
- package/dist/runnables/config.cjs +30 -8
- package/dist/runnables/config.js +30 -8
- package/dist/runnables/history.cjs +1 -1
- package/dist/runnables/history.d.ts +1 -3
- package/dist/runnables/history.js +1 -1
- package/dist/runnables/index.cjs +2 -1
- package/dist/runnables/index.d.ts +1 -1
- package/dist/runnables/index.js +1 -1
- package/dist/runnables/tests/runnable.test.js +3 -3
- package/dist/runnables/tests/runnable_stream_events.test.js +1 -1
- package/dist/runnables/tests/runnable_stream_events_v2.test.js +124 -19
- package/dist/runnables/tests/runnable_tools.test.d.ts +1 -0
- package/dist/runnables/tests/runnable_tools.test.js +111 -0
- package/dist/singletons/tests/async_local_storage.test.js +38 -4
- package/dist/{tools.cjs → tools/index.cjs} +130 -14
- package/dist/{tools.d.ts → tools/index.d.ts} +69 -31
- package/dist/{tools.js → tools/index.js} +130 -14
- package/dist/tools/tests/tools.test.d.ts +1 -0
- package/dist/tools/tests/tools.test.js +74 -0
- package/dist/tracers/base.cjs +1 -0
- package/dist/tracers/base.d.ts +1 -1
- package/dist/tracers/base.js +1 -0
- package/dist/tracers/event_stream.cjs +15 -0
- package/dist/tracers/event_stream.d.ts +1 -0
- package/dist/tracers/event_stream.js +15 -0
- package/dist/tracers/initialize.cjs +2 -0
- package/dist/tracers/initialize.d.ts +2 -0
- package/dist/tracers/initialize.js +2 -0
- package/dist/types/zod.cjs +2 -0
- package/dist/types/zod.d.ts +2 -0
- package/dist/types/zod.js +1 -0
- package/dist/utils/callbacks.cjs +17 -0
- package/dist/utils/callbacks.d.ts +1 -0
- package/dist/utils/callbacks.js +13 -0
- package/dist/utils/function_calling.cjs +38 -10
- package/dist/utils/function_calling.d.ts +32 -11
- package/dist/utils/function_calling.js +36 -9
- package/dist/utils/testing/index.cjs +10 -3
- package/dist/utils/testing/index.d.ts +1 -1
- package/dist/utils/testing/index.js +9 -2
- package/package.json +28 -14
- package/tools.cjs +1 -1
- package/tools.d.cts +1 -1
- package/tools.d.ts +1 -1
- package/tools.js +1 -1
- package/dist/utils/beta_warning.cjs +0 -11
- package/dist/utils/beta_warning.d.ts +0 -5
- package/dist/utils/beta_warning.js +0 -7
- package/utils/beta_warning.cjs +0 -1
- package/utils/beta_warning.d.cts +0 -1
- package/utils/beta_warning.d.ts +0 -1
- package/utils/beta_warning.js +0 -1
|
@@ -7,10 +7,12 @@ import { RunnableLambda, RunnableMap, RunnablePassthrough, RunnablePick, } from
|
|
|
7
7
|
import { ChatPromptTemplate } from "../../prompts/chat.js";
|
|
8
8
|
import { FakeChatModel, FakeLLM, FakeListChatModel, FakeRetriever, FakeStreamingLLM, } from "../../utils/testing/index.js";
|
|
9
9
|
import { AIMessage, AIMessageChunk, HumanMessage, SystemMessage, } from "../../messages/index.js";
|
|
10
|
-
import { DynamicStructuredTool, DynamicTool, tool } from "../../tools.js";
|
|
10
|
+
import { DynamicStructuredTool, DynamicTool, tool } from "../../tools/index.js";
|
|
11
11
|
import { Document } from "../../documents/document.js";
|
|
12
12
|
import { PromptTemplate } from "../../prompts/prompt.js";
|
|
13
13
|
import { GenerationChunk } from "../../outputs.js";
|
|
14
|
+
// Import from web to avoid side-effects from AsyncLocalStorage
|
|
15
|
+
import { dispatchCustomEvent } from "../../callbacks/dispatch/web.js";
|
|
14
16
|
function reverse(s) {
|
|
15
17
|
// Reverse a string.
|
|
16
18
|
return s.split("").reverse().join("");
|
|
@@ -958,7 +960,7 @@ test("Chat model that supports streaming, but is invoked, should still emit on_s
|
|
|
958
960
|
event: "on_chat_model_start",
|
|
959
961
|
name: "my_model",
|
|
960
962
|
run_id: expect.any(String),
|
|
961
|
-
tags: expect.arrayContaining(["
|
|
963
|
+
tags: expect.arrayContaining(["my_model", "my_chain"]),
|
|
962
964
|
metadata: {
|
|
963
965
|
foo: "bar",
|
|
964
966
|
a: "b",
|
|
@@ -976,7 +978,7 @@ test("Chat model that supports streaming, but is invoked, should still emit on_s
|
|
|
976
978
|
{
|
|
977
979
|
event: "on_chat_model_stream",
|
|
978
980
|
run_id: expect.any(String),
|
|
979
|
-
tags: expect.arrayContaining(["my_chain", "my_model"
|
|
981
|
+
tags: expect.arrayContaining(["my_chain", "my_model"]),
|
|
980
982
|
metadata: {
|
|
981
983
|
a: "b",
|
|
982
984
|
foo: "bar",
|
|
@@ -989,7 +991,7 @@ test("Chat model that supports streaming, but is invoked, should still emit on_s
|
|
|
989
991
|
{
|
|
990
992
|
event: "on_chat_model_stream",
|
|
991
993
|
run_id: expect.any(String),
|
|
992
|
-
tags: expect.arrayContaining(["my_chain", "my_model"
|
|
994
|
+
tags: expect.arrayContaining(["my_chain", "my_model"]),
|
|
993
995
|
metadata: {
|
|
994
996
|
a: "b",
|
|
995
997
|
foo: "bar",
|
|
@@ -1002,7 +1004,7 @@ test("Chat model that supports streaming, but is invoked, should still emit on_s
|
|
|
1002
1004
|
{
|
|
1003
1005
|
event: "on_chat_model_stream",
|
|
1004
1006
|
run_id: expect.any(String),
|
|
1005
|
-
tags: expect.arrayContaining(["my_chain", "my_model"
|
|
1007
|
+
tags: expect.arrayContaining(["my_chain", "my_model"]),
|
|
1006
1008
|
metadata: {
|
|
1007
1009
|
a: "b",
|
|
1008
1010
|
foo: "bar",
|
|
@@ -1015,7 +1017,7 @@ test("Chat model that supports streaming, but is invoked, should still emit on_s
|
|
|
1015
1017
|
{
|
|
1016
1018
|
event: "on_chat_model_stream",
|
|
1017
1019
|
run_id: expect.any(String),
|
|
1018
|
-
tags: expect.arrayContaining(["my_chain", "my_model"
|
|
1020
|
+
tags: expect.arrayContaining(["my_chain", "my_model"]),
|
|
1019
1021
|
metadata: {
|
|
1020
1022
|
a: "b",
|
|
1021
1023
|
foo: "bar",
|
|
@@ -1029,7 +1031,7 @@ test("Chat model that supports streaming, but is invoked, should still emit on_s
|
|
|
1029
1031
|
event: "on_chat_model_end",
|
|
1030
1032
|
name: "my_model",
|
|
1031
1033
|
run_id: expect.any(String),
|
|
1032
|
-
tags: expect.arrayContaining(["
|
|
1034
|
+
tags: expect.arrayContaining(["my_model", "my_chain"]),
|
|
1033
1035
|
metadata: {
|
|
1034
1036
|
foo: "bar",
|
|
1035
1037
|
a: "b",
|
|
@@ -1172,7 +1174,7 @@ test("Chat model that doesn't support streaming, but is invoked, should emit one
|
|
|
1172
1174
|
event: "on_chat_model_start",
|
|
1173
1175
|
name: "my_model",
|
|
1174
1176
|
run_id: expect.any(String),
|
|
1175
|
-
tags: expect.arrayContaining(["
|
|
1177
|
+
tags: expect.arrayContaining(["my_model", "my_chain"]),
|
|
1176
1178
|
metadata: {
|
|
1177
1179
|
foo: "bar",
|
|
1178
1180
|
a: "b",
|
|
@@ -1190,7 +1192,7 @@ test("Chat model that doesn't support streaming, but is invoked, should emit one
|
|
|
1190
1192
|
{
|
|
1191
1193
|
event: "on_chat_model_stream",
|
|
1192
1194
|
run_id: expect.any(String),
|
|
1193
|
-
tags: expect.arrayContaining(["my_chain", "my_model"
|
|
1195
|
+
tags: expect.arrayContaining(["my_chain", "my_model"]),
|
|
1194
1196
|
metadata: {
|
|
1195
1197
|
a: "b",
|
|
1196
1198
|
foo: "bar",
|
|
@@ -1204,7 +1206,7 @@ test("Chat model that doesn't support streaming, but is invoked, should emit one
|
|
|
1204
1206
|
event: "on_chat_model_end",
|
|
1205
1207
|
name: "my_model",
|
|
1206
1208
|
run_id: expect.any(String),
|
|
1207
|
-
tags: expect.arrayContaining(["
|
|
1209
|
+
tags: expect.arrayContaining(["my_model", "my_chain"]),
|
|
1208
1210
|
metadata: {
|
|
1209
1211
|
foo: "bar",
|
|
1210
1212
|
a: "b",
|
|
@@ -1356,7 +1358,7 @@ test("LLM that supports streaming, but is invoked, should still emit on_stream e
|
|
|
1356
1358
|
},
|
|
1357
1359
|
},
|
|
1358
1360
|
name: "my_model",
|
|
1359
|
-
tags: ["
|
|
1361
|
+
tags: ["my_model", "my_chain"],
|
|
1360
1362
|
run_id: expect.any(String),
|
|
1361
1363
|
metadata: {
|
|
1362
1364
|
foo: "bar",
|
|
@@ -1372,7 +1374,7 @@ test("LLM that supports streaming, but is invoked, should still emit on_stream e
|
|
|
1372
1374
|
},
|
|
1373
1375
|
run_id: expect.any(String),
|
|
1374
1376
|
name: "my_model",
|
|
1375
|
-
tags: ["
|
|
1377
|
+
tags: ["my_model", "my_chain"],
|
|
1376
1378
|
metadata: {
|
|
1377
1379
|
foo: "bar",
|
|
1378
1380
|
a: "b",
|
|
@@ -1387,7 +1389,7 @@ test("LLM that supports streaming, but is invoked, should still emit on_stream e
|
|
|
1387
1389
|
},
|
|
1388
1390
|
run_id: expect.any(String),
|
|
1389
1391
|
name: "my_model",
|
|
1390
|
-
tags: ["
|
|
1392
|
+
tags: ["my_model", "my_chain"],
|
|
1391
1393
|
metadata: {
|
|
1392
1394
|
foo: "bar",
|
|
1393
1395
|
a: "b",
|
|
@@ -1402,7 +1404,7 @@ test("LLM that supports streaming, but is invoked, should still emit on_stream e
|
|
|
1402
1404
|
},
|
|
1403
1405
|
run_id: expect.any(String),
|
|
1404
1406
|
name: "my_model",
|
|
1405
|
-
tags: ["
|
|
1407
|
+
tags: ["my_model", "my_chain"],
|
|
1406
1408
|
metadata: {
|
|
1407
1409
|
foo: "bar",
|
|
1408
1410
|
a: "b",
|
|
@@ -1417,7 +1419,7 @@ test("LLM that supports streaming, but is invoked, should still emit on_stream e
|
|
|
1417
1419
|
},
|
|
1418
1420
|
run_id: expect.any(String),
|
|
1419
1421
|
name: "my_model",
|
|
1420
|
-
tags: ["
|
|
1422
|
+
tags: ["my_model", "my_chain"],
|
|
1421
1423
|
metadata: {
|
|
1422
1424
|
foo: "bar",
|
|
1423
1425
|
a: "b",
|
|
@@ -1443,7 +1445,7 @@ test("LLM that supports streaming, but is invoked, should still emit on_stream e
|
|
|
1443
1445
|
},
|
|
1444
1446
|
run_id: expect.any(String),
|
|
1445
1447
|
name: "my_model",
|
|
1446
|
-
tags: ["
|
|
1448
|
+
tags: ["my_model", "my_chain"],
|
|
1447
1449
|
metadata: {
|
|
1448
1450
|
foo: "bar",
|
|
1449
1451
|
a: "b",
|
|
@@ -1587,7 +1589,7 @@ test("LLM that doesn't support streaming, but is invoked, should emit one on_str
|
|
|
1587
1589
|
},
|
|
1588
1590
|
},
|
|
1589
1591
|
name: "my_model",
|
|
1590
|
-
tags: ["
|
|
1592
|
+
tags: ["my_model", "my_chain"],
|
|
1591
1593
|
run_id: expect.any(String),
|
|
1592
1594
|
metadata: {
|
|
1593
1595
|
foo: "bar",
|
|
@@ -1603,7 +1605,7 @@ test("LLM that doesn't support streaming, but is invoked, should emit one on_str
|
|
|
1603
1605
|
},
|
|
1604
1606
|
run_id: expect.any(String),
|
|
1605
1607
|
name: "my_model",
|
|
1606
|
-
tags: ["
|
|
1608
|
+
tags: ["my_model", "my_chain"],
|
|
1607
1609
|
metadata: {
|
|
1608
1610
|
foo: "bar",
|
|
1609
1611
|
a: "b",
|
|
@@ -1629,7 +1631,7 @@ test("LLM that doesn't support streaming, but is invoked, should emit one on_str
|
|
|
1629
1631
|
},
|
|
1630
1632
|
run_id: expect.any(String),
|
|
1631
1633
|
name: "my_model",
|
|
1632
|
-
tags: ["
|
|
1634
|
+
tags: ["my_model", "my_chain"],
|
|
1633
1635
|
metadata: {
|
|
1634
1636
|
foo: "bar",
|
|
1635
1637
|
a: "b",
|
|
@@ -1748,6 +1750,109 @@ test("Runnable streamEvents method with simple tools", async () => {
|
|
|
1748
1750
|
},
|
|
1749
1751
|
]);
|
|
1750
1752
|
});
|
|
1753
|
+
test("Runnable streamEvents method with a custom event", async () => {
|
|
1754
|
+
const lambda = RunnableLambda.from(async (params, config) => {
|
|
1755
|
+
await dispatchCustomEvent("testEvent", { someval: "test" }, config);
|
|
1756
|
+
await dispatchCustomEvent("testEvent", { someval: "test2" }, config);
|
|
1757
|
+
return JSON.stringify({ x: params.x, y: params.y });
|
|
1758
|
+
});
|
|
1759
|
+
const events = [];
|
|
1760
|
+
const eventStream = await lambda.streamEvents({ x: 1, y: "2" }, { version: "v2" });
|
|
1761
|
+
for await (const event of eventStream) {
|
|
1762
|
+
events.push(event);
|
|
1763
|
+
}
|
|
1764
|
+
expect(events).toEqual([
|
|
1765
|
+
{
|
|
1766
|
+
event: "on_chain_start",
|
|
1767
|
+
data: { input: { x: 1, y: "2" } },
|
|
1768
|
+
name: "RunnableLambda",
|
|
1769
|
+
tags: [],
|
|
1770
|
+
run_id: expect.any(String),
|
|
1771
|
+
metadata: {},
|
|
1772
|
+
},
|
|
1773
|
+
{
|
|
1774
|
+
event: "on_custom_event",
|
|
1775
|
+
run_id: expect.any(String),
|
|
1776
|
+
name: "testEvent",
|
|
1777
|
+
tags: [],
|
|
1778
|
+
metadata: {},
|
|
1779
|
+
data: { someval: "test" },
|
|
1780
|
+
},
|
|
1781
|
+
{
|
|
1782
|
+
event: "on_custom_event",
|
|
1783
|
+
run_id: expect.any(String),
|
|
1784
|
+
name: "testEvent",
|
|
1785
|
+
tags: [],
|
|
1786
|
+
metadata: {},
|
|
1787
|
+
data: { someval: "test2" },
|
|
1788
|
+
},
|
|
1789
|
+
{
|
|
1790
|
+
event: "on_chain_stream",
|
|
1791
|
+
run_id: expect.any(String),
|
|
1792
|
+
name: "RunnableLambda",
|
|
1793
|
+
tags: [],
|
|
1794
|
+
metadata: {},
|
|
1795
|
+
data: { chunk: '{"x":1,"y":"2"}' },
|
|
1796
|
+
},
|
|
1797
|
+
{
|
|
1798
|
+
event: "on_chain_end",
|
|
1799
|
+
data: { output: '{"x":1,"y":"2"}' },
|
|
1800
|
+
run_id: expect.any(String),
|
|
1801
|
+
name: "RunnableLambda",
|
|
1802
|
+
tags: [],
|
|
1803
|
+
metadata: {},
|
|
1804
|
+
},
|
|
1805
|
+
]);
|
|
1806
|
+
});
|
|
1807
|
+
test("Custom event inside a custom tool", async () => {
|
|
1808
|
+
const customTool = tool(async (params, config) => {
|
|
1809
|
+
await dispatchCustomEvent("testEvent", { someval: "test" }, config);
|
|
1810
|
+
await dispatchCustomEvent("testEvent", { someval: "test2" }, config);
|
|
1811
|
+
return JSON.stringify({ x: params.x, y: params.y });
|
|
1812
|
+
}, {
|
|
1813
|
+
schema: z.object({ x: z.number(), y: z.string() }),
|
|
1814
|
+
name: "testtool",
|
|
1815
|
+
});
|
|
1816
|
+
const events = [];
|
|
1817
|
+
const eventStream = await customTool.streamEvents({ x: 1, y: "2" }, { version: "v2" });
|
|
1818
|
+
for await (const event of eventStream) {
|
|
1819
|
+
events.push(event);
|
|
1820
|
+
}
|
|
1821
|
+
expect(events).toEqual([
|
|
1822
|
+
{
|
|
1823
|
+
event: "on_tool_start",
|
|
1824
|
+
data: { input: { x: 1, y: "2" } },
|
|
1825
|
+
name: "testtool",
|
|
1826
|
+
tags: [],
|
|
1827
|
+
run_id: expect.any(String),
|
|
1828
|
+
metadata: {},
|
|
1829
|
+
},
|
|
1830
|
+
{
|
|
1831
|
+
event: "on_custom_event",
|
|
1832
|
+
run_id: expect.any(String),
|
|
1833
|
+
name: "testEvent",
|
|
1834
|
+
tags: [],
|
|
1835
|
+
metadata: {},
|
|
1836
|
+
data: { someval: "test" },
|
|
1837
|
+
},
|
|
1838
|
+
{
|
|
1839
|
+
event: "on_custom_event",
|
|
1840
|
+
run_id: expect.any(String),
|
|
1841
|
+
name: "testEvent",
|
|
1842
|
+
tags: [],
|
|
1843
|
+
metadata: {},
|
|
1844
|
+
data: { someval: "test2" },
|
|
1845
|
+
},
|
|
1846
|
+
{
|
|
1847
|
+
event: "on_tool_end",
|
|
1848
|
+
data: { output: '{"x":1,"y":"2"}' },
|
|
1849
|
+
run_id: expect.any(String),
|
|
1850
|
+
name: "testtool",
|
|
1851
|
+
tags: [],
|
|
1852
|
+
metadata: {},
|
|
1853
|
+
},
|
|
1854
|
+
]);
|
|
1855
|
+
});
|
|
1751
1856
|
test("Runnable streamEvents method with tools that return objects", async () => {
|
|
1752
1857
|
const adderFunc = (_params) => {
|
|
1753
1858
|
return JSON.stringify({ sum: 3 });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { RunnableLambda, RunnableToolLike } from "../base.js";
|
|
3
|
+
test("Runnable asTool works", async () => {
|
|
4
|
+
const schema = z.object({
|
|
5
|
+
foo: z.string(),
|
|
6
|
+
});
|
|
7
|
+
const runnable = RunnableLambda.from((input, config) => {
|
|
8
|
+
return `${input.foo}${config?.configurable.foo}`;
|
|
9
|
+
});
|
|
10
|
+
const tool = runnable.asTool({
|
|
11
|
+
schema,
|
|
12
|
+
});
|
|
13
|
+
expect(tool).toBeInstanceOf(RunnableToolLike);
|
|
14
|
+
expect(tool.schema).toBe(schema);
|
|
15
|
+
expect(tool.name).toBe(runnable.getName());
|
|
16
|
+
});
|
|
17
|
+
test("Runnable asTool works with all populated fields", async () => {
|
|
18
|
+
const schema = z.object({
|
|
19
|
+
foo: z.string(),
|
|
20
|
+
});
|
|
21
|
+
const runnable = RunnableLambda.from((input, config) => {
|
|
22
|
+
return `${input.foo}${config?.configurable.foo}`;
|
|
23
|
+
});
|
|
24
|
+
const tool = runnable.asTool({
|
|
25
|
+
schema,
|
|
26
|
+
name: "test",
|
|
27
|
+
description: "test",
|
|
28
|
+
});
|
|
29
|
+
expect(tool).toBeInstanceOf(RunnableToolLike);
|
|
30
|
+
expect(tool.schema).toBe(schema);
|
|
31
|
+
expect(tool.description).toBe("test");
|
|
32
|
+
expect(tool.name).toBe("test");
|
|
33
|
+
});
|
|
34
|
+
test("Runnable asTool can invoke", async () => {
|
|
35
|
+
const schema = z.object({
|
|
36
|
+
foo: z.string(),
|
|
37
|
+
});
|
|
38
|
+
const runnable = RunnableLambda.from((input, config) => {
|
|
39
|
+
return `${input.foo}${config?.configurable.foo}`;
|
|
40
|
+
});
|
|
41
|
+
const tool = runnable.asTool({
|
|
42
|
+
schema,
|
|
43
|
+
});
|
|
44
|
+
const toolResponse = await tool.invoke({
|
|
45
|
+
foo: "bar",
|
|
46
|
+
}, {
|
|
47
|
+
configurable: {
|
|
48
|
+
foo: "bar",
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
expect(toolResponse).toBe("barbar");
|
|
52
|
+
});
|
|
53
|
+
test("asTool should type error with mismatched schema", async () => {
|
|
54
|
+
// asTool infers the type of the Zod schema from the existing runnable's RunInput generic.
|
|
55
|
+
// If the Zod schema does not match the RunInput, it should throw a type error.
|
|
56
|
+
const schema = z.object({
|
|
57
|
+
foo: z.string(),
|
|
58
|
+
});
|
|
59
|
+
const runnable = RunnableLambda.from((input, config) => {
|
|
60
|
+
return `${input.bar}${config?.configurable.foo}`;
|
|
61
|
+
});
|
|
62
|
+
runnable.asTool({
|
|
63
|
+
// @ts-expect-error - Should error. If this does not give a type error, the generics/typing of `asTool` is broken.
|
|
64
|
+
schema,
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
test("Create a runnable tool directly from RunnableToolLike", async () => {
|
|
68
|
+
const schema = z.object({
|
|
69
|
+
foo: z.string(),
|
|
70
|
+
});
|
|
71
|
+
const adderFunc = (_) => {
|
|
72
|
+
return Promise.resolve(true);
|
|
73
|
+
};
|
|
74
|
+
const tool = new RunnableToolLike({
|
|
75
|
+
schema,
|
|
76
|
+
name: "test",
|
|
77
|
+
description: "test",
|
|
78
|
+
bound: RunnableLambda.from(adderFunc),
|
|
79
|
+
});
|
|
80
|
+
const result = await tool.invoke({ foo: "bar" });
|
|
81
|
+
expect(result).toBe(true);
|
|
82
|
+
});
|
|
83
|
+
test("asTool can take a single string input", async () => {
|
|
84
|
+
const firstRunnable = RunnableLambda.from((input) => {
|
|
85
|
+
return `${input}a`;
|
|
86
|
+
});
|
|
87
|
+
const secondRunnable = RunnableLambda.from((input) => {
|
|
88
|
+
return `${input}z`;
|
|
89
|
+
});
|
|
90
|
+
const runnable = firstRunnable.pipe(secondRunnable);
|
|
91
|
+
const asTool = runnable.asTool({
|
|
92
|
+
schema: z.string(),
|
|
93
|
+
});
|
|
94
|
+
const result = await asTool.invoke("b");
|
|
95
|
+
expect(result).toBe("baz");
|
|
96
|
+
});
|
|
97
|
+
test("Runnable asTool uses Zod schema description if not provided", async () => {
|
|
98
|
+
const description = "Test schema";
|
|
99
|
+
const schema = z
|
|
100
|
+
.object({
|
|
101
|
+
foo: z.string(),
|
|
102
|
+
})
|
|
103
|
+
.describe(description);
|
|
104
|
+
const runnable = RunnableLambda.from((input, config) => {
|
|
105
|
+
return `${input.foo}${config?.configurable.foo}`;
|
|
106
|
+
});
|
|
107
|
+
const tool = runnable.asTool({
|
|
108
|
+
schema,
|
|
109
|
+
});
|
|
110
|
+
expect(tool.description).toBe(description);
|
|
111
|
+
});
|
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import { test, expect } from "@jest/globals";
|
|
2
|
+
import { v4 } from "uuid";
|
|
2
3
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
4
|
import { AsyncLocalStorageProviderSingleton } from "../index.js";
|
|
4
5
|
import { RunnableLambda } from "../../runnables/base.js";
|
|
5
6
|
import { FakeListChatModel } from "../../utils/testing/index.js";
|
|
7
|
+
import { getCallbackManagerForConfig } from "../../runnables/config.js";
|
|
8
|
+
import { BaseCallbackHandler } from "../../callbacks/base.js";
|
|
9
|
+
class FakeCallbackHandler extends BaseCallbackHandler {
|
|
10
|
+
constructor() {
|
|
11
|
+
super(...arguments);
|
|
12
|
+
Object.defineProperty(this, "name", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
configurable: true,
|
|
15
|
+
writable: true,
|
|
16
|
+
value: `fake-${v4()}`
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
6
20
|
test("Config should be automatically populated after setting global async local storage", async () => {
|
|
7
21
|
const inner = RunnableLambda.from((_, config) => config);
|
|
8
22
|
const outer = RunnableLambda.from(async (input) => {
|
|
@@ -32,7 +46,6 @@ test("Config should be automatically populated after setting global async local
|
|
|
32
46
|
});
|
|
33
47
|
const chunks = [];
|
|
34
48
|
for await (const chunk of stream) {
|
|
35
|
-
console.log(chunk);
|
|
36
49
|
chunks.push(chunk);
|
|
37
50
|
}
|
|
38
51
|
expect(chunks.length).toEqual(1);
|
|
@@ -58,7 +71,6 @@ test("Config should be automatically populated after setting global async local
|
|
|
58
71
|
});
|
|
59
72
|
const chunks2 = [];
|
|
60
73
|
for await (const chunk of stream2) {
|
|
61
|
-
console.log(chunk);
|
|
62
74
|
chunks2.push(chunk);
|
|
63
75
|
}
|
|
64
76
|
expect(chunks2.length).toEqual(1);
|
|
@@ -90,17 +102,38 @@ test("Config should be automatically populated after setting global async local
|
|
|
90
102
|
const eventStream = await outer4.streamEvents({ hi: true }, { version: "v1" });
|
|
91
103
|
const events = [];
|
|
92
104
|
for await (const event of eventStream) {
|
|
93
|
-
console.log(event);
|
|
94
105
|
events.push(event);
|
|
95
106
|
}
|
|
96
107
|
expect(events.filter((event) => event.event === "on_llm_start").length).toEqual(1);
|
|
97
108
|
});
|
|
98
109
|
test("Runnable streamEvents method with streaming nested in a RunnableLambda", async () => {
|
|
99
110
|
AsyncLocalStorageProviderSingleton.initializeGlobalInstance(new AsyncLocalStorage());
|
|
111
|
+
const asyncLocalStorage = AsyncLocalStorageProviderSingleton.getInstance();
|
|
100
112
|
const chat = new FakeListChatModel({
|
|
101
113
|
responses: ["Hello"],
|
|
102
114
|
});
|
|
115
|
+
const outerRunId = v4();
|
|
116
|
+
const innerRunId = v4();
|
|
117
|
+
const innerRunId2 = v4();
|
|
118
|
+
const dummyHandler = new FakeCallbackHandler();
|
|
103
119
|
const myFunc = async (input) => {
|
|
120
|
+
const outerCallbackManager = await getCallbackManagerForConfig(asyncLocalStorage.getStore());
|
|
121
|
+
expect(outerCallbackManager?.getParentRunId()).toEqual(outerRunId);
|
|
122
|
+
const nestedLambdaWithOverriddenCallbacks = RunnableLambda.from(async (_, config) => {
|
|
123
|
+
expect(config?.callbacks?.handlers).toEqual([]);
|
|
124
|
+
});
|
|
125
|
+
await nestedLambdaWithOverriddenCallbacks.invoke(input, {
|
|
126
|
+
runId: innerRunId,
|
|
127
|
+
callbacks: [],
|
|
128
|
+
});
|
|
129
|
+
const nestedLambdaWithoutOverriddenCallbacks = RunnableLambda.from(async (_, config) => {
|
|
130
|
+
const innerCallbackManager = await getCallbackManagerForConfig(asyncLocalStorage.getStore());
|
|
131
|
+
expect(innerCallbackManager?.getParentRunId()).toEqual(innerRunId2);
|
|
132
|
+
expect(config?.callbacks?.handlers).toContain(dummyHandler);
|
|
133
|
+
});
|
|
134
|
+
await nestedLambdaWithoutOverriddenCallbacks.invoke(input, {
|
|
135
|
+
runId: innerRunId2,
|
|
136
|
+
});
|
|
104
137
|
for await (const _ of await chat.stream(input)) {
|
|
105
138
|
// no-op
|
|
106
139
|
}
|
|
@@ -109,8 +142,9 @@ test("Runnable streamEvents method with streaming nested in a RunnableLambda", a
|
|
|
109
142
|
const events = [];
|
|
110
143
|
for await (const event of myNestedLambda.streamEvents("hello", {
|
|
111
144
|
version: "v1",
|
|
145
|
+
runId: outerRunId,
|
|
146
|
+
callbacks: [dummyHandler],
|
|
112
147
|
})) {
|
|
113
|
-
console.log(event);
|
|
114
148
|
events.push(event);
|
|
115
149
|
}
|
|
116
150
|
const chatModelStreamEvent = events.find((event) => {
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.tool = exports.BaseToolkit = exports.DynamicStructuredTool = exports.DynamicTool = exports.Tool = exports.StructuredTool = exports.ToolInputParsingException = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
-
const manager_js_1 = require("
|
|
6
|
-
const base_js_1 = require("
|
|
7
|
-
const config_js_1 = require("
|
|
5
|
+
const manager_js_1 = require("../callbacks/manager.cjs");
|
|
6
|
+
const base_js_1 = require("../language_models/base.cjs");
|
|
7
|
+
const config_js_1 = require("../runnables/config.cjs");
|
|
8
|
+
const tool_js_1 = require("../messages/tool.cjs");
|
|
9
|
+
const index_js_1 = require("../singletons/index.cjs");
|
|
8
10
|
/**
|
|
9
11
|
* Custom error class used to handle exceptions related to tool input parsing.
|
|
10
12
|
* It extends the built-in `Error` class and adds an optional `output`
|
|
@@ -38,6 +40,22 @@ class StructuredTool extends base_js_1.BaseLangChain {
|
|
|
38
40
|
writable: true,
|
|
39
41
|
value: false
|
|
40
42
|
});
|
|
43
|
+
/**
|
|
44
|
+
* The tool response format.
|
|
45
|
+
*
|
|
46
|
+
* If "content" then the output of the tool is interpreted as the contents of a
|
|
47
|
+
* ToolMessage. If "content_and_artifact" then the output is expected to be a
|
|
48
|
+
* two-tuple corresponding to the (content, artifact) of a ToolMessage.
|
|
49
|
+
*
|
|
50
|
+
* @default "content"
|
|
51
|
+
*/
|
|
52
|
+
Object.defineProperty(this, "responseFormat", {
|
|
53
|
+
enumerable: true,
|
|
54
|
+
configurable: true,
|
|
55
|
+
writable: true,
|
|
56
|
+
value: "content"
|
|
57
|
+
});
|
|
58
|
+
this.responseFormat = fields?.responseFormat ?? this.responseFormat;
|
|
41
59
|
}
|
|
42
60
|
/**
|
|
43
61
|
* Invokes the tool with the provided input and configuration.
|
|
@@ -46,7 +64,23 @@ class StructuredTool extends base_js_1.BaseLangChain {
|
|
|
46
64
|
* @returns A Promise that resolves with a string.
|
|
47
65
|
*/
|
|
48
66
|
async invoke(input, config) {
|
|
49
|
-
|
|
67
|
+
let tool_call_id;
|
|
68
|
+
let toolInput;
|
|
69
|
+
if (_isToolCall(input)) {
|
|
70
|
+
tool_call_id = input.id;
|
|
71
|
+
toolInput = input.args;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
toolInput = input;
|
|
75
|
+
}
|
|
76
|
+
const ensuredConfig = (0, config_js_1.ensureConfig)(config);
|
|
77
|
+
return this.call(toolInput, {
|
|
78
|
+
...ensuredConfig,
|
|
79
|
+
configurable: {
|
|
80
|
+
...ensuredConfig.configurable,
|
|
81
|
+
tool_call_id,
|
|
82
|
+
},
|
|
83
|
+
});
|
|
50
84
|
}
|
|
51
85
|
/**
|
|
52
86
|
* @deprecated Use .invoke() instead. Will be removed in 0.3.0.
|
|
@@ -81,8 +115,32 @@ class StructuredTool extends base_js_1.BaseLangChain {
|
|
|
81
115
|
await runManager?.handleToolError(e);
|
|
82
116
|
throw e;
|
|
83
117
|
}
|
|
84
|
-
|
|
85
|
-
|
|
118
|
+
let content;
|
|
119
|
+
let artifact;
|
|
120
|
+
if (this.responseFormat === "content_and_artifact") {
|
|
121
|
+
if (Array.isArray(result) && result.length === 2) {
|
|
122
|
+
[content, artifact] = result;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
throw new Error(`Tool response format is "content_and_artifact" but the output was not a two-tuple.\nResult: ${JSON.stringify(result)}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
content = result;
|
|
130
|
+
}
|
|
131
|
+
let toolCallId;
|
|
132
|
+
if (config && "configurable" in config) {
|
|
133
|
+
toolCallId = config.configurable
|
|
134
|
+
.tool_call_id;
|
|
135
|
+
}
|
|
136
|
+
const formattedOutput = _formatToolOutput({
|
|
137
|
+
content,
|
|
138
|
+
artifact,
|
|
139
|
+
toolCallId,
|
|
140
|
+
name: this.name,
|
|
141
|
+
});
|
|
142
|
+
await runManager?.handleToolEnd(formattedOutput);
|
|
143
|
+
return formattedOutput;
|
|
86
144
|
}
|
|
87
145
|
}
|
|
88
146
|
exports.StructuredTool = StructuredTool;
|
|
@@ -158,8 +216,8 @@ class DynamicTool extends Tool {
|
|
|
158
216
|
return super.call(arg, config);
|
|
159
217
|
}
|
|
160
218
|
/** @ignore */
|
|
161
|
-
async _call(input, runManager,
|
|
162
|
-
return this.func(input, runManager,
|
|
219
|
+
async _call(input, runManager, parentConfig) {
|
|
220
|
+
return this.func(input, runManager, parentConfig);
|
|
163
221
|
}
|
|
164
222
|
}
|
|
165
223
|
exports.DynamicTool = DynamicTool;
|
|
@@ -217,8 +275,8 @@ class DynamicStructuredTool extends StructuredTool {
|
|
|
217
275
|
}
|
|
218
276
|
return super.call(arg, config, tags);
|
|
219
277
|
}
|
|
220
|
-
_call(arg, runManager,
|
|
221
|
-
return this.func(arg, runManager,
|
|
278
|
+
_call(arg, runManager, parentConfig) {
|
|
279
|
+
return this.func(arg, runManager, parentConfig);
|
|
222
280
|
}
|
|
223
281
|
}
|
|
224
282
|
exports.DynamicStructuredTool = DynamicStructuredTool;
|
|
@@ -236,15 +294,17 @@ exports.BaseToolkit = BaseToolkit;
|
|
|
236
294
|
/**
|
|
237
295
|
* Creates a new StructuredTool instance with the provided function, name, description, and schema.
|
|
238
296
|
* @function
|
|
239
|
-
* @template {ZodAny} RunInput The input schema for the tool.
|
|
297
|
+
* @template {RunInput extends ZodAny = ZodAny} RunInput The input schema for the tool. This corresponds to the input type when the tool is invoked.
|
|
298
|
+
* @template {RunOutput = any} RunOutput The output type for the tool. This corresponds to the output type when the tool is invoked.
|
|
299
|
+
* @template {FuncInput extends z.infer<RunInput> | ToolCall = z.infer<RunInput>} FuncInput The input type for the function.
|
|
240
300
|
*
|
|
241
|
-
* @param {RunnableFunc<RunInput,
|
|
301
|
+
* @param {RunnableFunc<z.infer<RunInput> | ToolCall, RunOutput>} func - The function to invoke when the tool is called.
|
|
242
302
|
* @param fields - An object containing the following properties:
|
|
243
303
|
* @param {string} fields.name The name of the tool.
|
|
244
304
|
* @param {string | undefined} fields.description The description of the tool. Defaults to either the description on the Zod schema, or `${fields.name} tool`.
|
|
245
305
|
* @param {z.ZodObject<any, any, any, any>} fields.schema The Zod schema defining the input for the tool.
|
|
246
306
|
*
|
|
247
|
-
* @returns {
|
|
307
|
+
* @returns {DynamicStructuredTool<RunInput, RunOutput>} A new StructuredTool instance.
|
|
248
308
|
*/
|
|
249
309
|
function tool(func, fields) {
|
|
250
310
|
const schema = fields.schema ??
|
|
@@ -254,7 +314,63 @@ function tool(func, fields) {
|
|
|
254
314
|
name: fields.name,
|
|
255
315
|
description,
|
|
256
316
|
schema: schema,
|
|
257
|
-
|
|
317
|
+
// TODO: Consider moving into DynamicStructuredTool constructor
|
|
318
|
+
func: async (input, runManager, config) => {
|
|
319
|
+
return new Promise((resolve, reject) => {
|
|
320
|
+
const childConfig = (0, config_js_1.patchConfig)(config, {
|
|
321
|
+
callbacks: runManager?.getChild(),
|
|
322
|
+
});
|
|
323
|
+
void index_js_1.AsyncLocalStorageProviderSingleton.getInstance().run(childConfig, async () => {
|
|
324
|
+
try {
|
|
325
|
+
resolve(func(input, childConfig));
|
|
326
|
+
}
|
|
327
|
+
catch (e) {
|
|
328
|
+
reject(e);
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
},
|
|
333
|
+
responseFormat: fields.responseFormat,
|
|
258
334
|
});
|
|
259
335
|
}
|
|
260
336
|
exports.tool = tool;
|
|
337
|
+
function _isToolCall(toolCall) {
|
|
338
|
+
return !!(toolCall &&
|
|
339
|
+
typeof toolCall === "object" &&
|
|
340
|
+
"type" in toolCall &&
|
|
341
|
+
toolCall.type === "tool_call");
|
|
342
|
+
}
|
|
343
|
+
function _formatToolOutput(params) {
|
|
344
|
+
const { content, artifact, toolCallId } = params;
|
|
345
|
+
if (toolCallId) {
|
|
346
|
+
if (typeof content === "string" ||
|
|
347
|
+
(Array.isArray(content) &&
|
|
348
|
+
content.every((item) => typeof item === "object"))) {
|
|
349
|
+
return new tool_js_1.ToolMessage({
|
|
350
|
+
content,
|
|
351
|
+
artifact,
|
|
352
|
+
tool_call_id: toolCallId,
|
|
353
|
+
name: params.name,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
return new tool_js_1.ToolMessage({
|
|
358
|
+
content: _stringify(content),
|
|
359
|
+
artifact,
|
|
360
|
+
tool_call_id: toolCallId,
|
|
361
|
+
name: params.name,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
return content;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
function _stringify(content) {
|
|
370
|
+
try {
|
|
371
|
+
return JSON.stringify(content, null, 2);
|
|
372
|
+
}
|
|
373
|
+
catch (_noOp) {
|
|
374
|
+
return `${content}`;
|
|
375
|
+
}
|
|
376
|
+
}
|