From 8992a55c23a1ae7fe650f8f4dd3d51f4777898a4 Mon Sep 17 00:00:00 2001 From: jacoblee93 Date: Tue, 16 Jul 2024 11:43:47 -0700 Subject: [PATCH 1/4] Adds docs for dispatching custom events --- .../docs/how_to/callbacks_custom_events.ipynb | 230 ++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 docs/core_docs/docs/how_to/callbacks_custom_events.ipynb diff --git a/docs/core_docs/docs/how_to/callbacks_custom_events.ipynb b/docs/core_docs/docs/how_to/callbacks_custom_events.ipynb new file mode 100644 index 000000000000..7a3e9e626f15 --- /dev/null +++ b/docs/core_docs/docs/how_to/callbacks_custom_events.ipynb @@ -0,0 +1,230 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# How to dispatch custom callback events\n", + "\n", + ":::info Prerequisites\n", + "\n", + "This guide assumes familiarity with the following concepts:\n", + "\n", + "- [Callbacks](/docs/concepts/#callbacks)\n", + "- [Custom callback handlers](/docs/how_to/custom_callbacks)\n", + "- [Stream Events API](/docs/concepts#streamevents)\n", + "\n", + ":::\n", + "\n", + "In some situations, you may want to dipsatch a custom callback event from within a [Runnable](/docs/concepts/#runnable-interface) so it can be surfaced\n", + "in a custom callback handler or via the [Stream Events API](/docs/concepts/#streamevents).\n", + "\n", + "For example, if you have a long running tool with multiple steps, you can dispatch custom events between the steps and use these custom events to monitor progress.\n", + "You could also surface these custom events to an end user of your application to show them how the current task is progressing.\n", + "\n", + "To dispatch a custom event you need to decide on two attributes for the event: the `name` and the `data`.\n", + "\n", + "| Attribute | Type | Description |\n", + "|-----------|------|----------------------------------------------------------------------------------------------------------|\n", + "| name | str | A user defined name for the event. |\n", + "| data | Any | The data associated with the event. This can be anything, though we suggest making it JSON serializable. |\n", + "\n", + "\n", + ":::info\n", + "- Custom callback events can only be dispatched from within an existing `Runnable`.\n", + "- If using `streamEvents`, you must use `version: \"v2\"` to see custom events.\n", + "- Sending or rendering custom callbacks events in LangSmith is not yet supported.\n", + ":::\n", + "\n", + "## Stream Events API\n", + "\n", + "The most useful way to consume custom events is via the [`.streamEvents()`](/docs/concepts/#astream_events) method.\n", + "\n", + "We can use the `dispatchCustomEvent` API to emit custom events in an async setting. \n", + "\n", + ":::caution Compatibility\n", + "Dispatching custom callback events requires `@langchain/core>=0.2.16`. See [this guide](/docs/how_to/installation/#installing-integration-packages) for some considerations to take when upgrading `@langchain/core`.\n", + "\n", + "The default entrypoint below triggers an import and initialization of [`async_hooks`](https://nodejs.org/api/async_hooks.html) to enable automatic `RunnableConfig` passing, which is not supported in all environments. If you see import issues, you must import from `@langchain/callbacks/dispatch/web` and propagate the `RunnableConfig` object manually (see example below).\n", + ":::" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " event: 'on_custom_event',\n", + " run_id: '9eac217d-3a2d-4563-a91f-3bd49bee4b3d',\n", + " name: 'event1',\n", + " tags: [],\n", + " metadata: {},\n", + " data: { reversed: 'dlrow olleh' }\n", + "}\n", + "{\n", + " event: 'on_custom_event',\n", + " run_id: '9eac217d-3a2d-4563-a91f-3bd49bee4b3d',\n", + " name: 'event2',\n", + " tags: [],\n", + " metadata: {},\n", + " data: 5\n", + "}\n" + ] + } + ], + "source": [ + "import { RunnableLambda } from \"@langchain/core/runnables\";\n", + "import { dispatchCustomEvent } from \"@langchain/core/callbacks/dispatch\";\n", + "\n", + "const reflect = RunnableLambda.from(async (value: string) => {\n", + " await dispatchCustomEvent(\"event1\", { reversed: value.split(\"\").reverse().join(\"\") });\n", + " await dispatchCustomEvent(\"event2\", 5);\n", + " return value;\n", + "});\n", + "\n", + "const eventStream = await reflect.streamEvents(\"hello world\", { version: \"v2\" });\n", + "\n", + "for await (const event of eventStream) {\n", + " if (event.event === \"on_custom_event\") {\n", + " console.log(event);\n", + " }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you are in a web environment that does not support `async_hooks`, you must import from the web entrypoint and propagate the config manually instead:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " event: 'on_custom_event',\n", + " run_id: 'dee1e4f0-c5ff-4118-9391-461a0dcc4cb2',\n", + " name: 'event1',\n", + " tags: [],\n", + " metadata: {},\n", + " data: { reversed: 'dlrow olleh' }\n", + "}\n", + "{\n", + " event: 'on_custom_event',\n", + " run_id: 'dee1e4f0-c5ff-4118-9391-461a0dcc4cb2',\n", + " name: 'event2',\n", + " tags: [],\n", + " metadata: {},\n", + " data: 5\n", + "}\n" + ] + } + ], + "source": [ + "import { RunnableConfig, RunnableLambda } from \"@langchain/core/runnables\";\n", + "import { dispatchCustomEvent as dispatchCustomEventWeb } from \"@langchain/core/callbacks/dispatch/web\";\n", + "\n", + "const reflect = RunnableLambda.from(async (value: string, config?: RunnableConfig) => {\n", + " await dispatchCustomEventWeb(\"event1\", { reversed: value.split(\"\").reverse().join(\"\") }, config);\n", + " await dispatchCustomEventWeb(\"event2\", 5, config);\n", + " return value;\n", + "});\n", + "\n", + "const eventStream = await reflect.streamEvents(\"hello world\", { version: \"v2\" });\n", + "\n", + "for await (const event of eventStream) {\n", + " if (event.event === \"on_custom_event\") {\n", + " console.log(event);\n", + " }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Callback Handler\n", + "\n", + "Let's see how to emit custom events in a sync environment with `dispatchCustomEvent`.\n", + "\n", + "Remember, you **must** call `dispatchCustomEvent` from within an existing `Runnable`." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "event1 { reversed: 'dlrow olleh' } 5f45eb5f-39df-4c78-aa36-8d1151823def\n", + "event2 5 5f45eb5f-39df-4c78-aa36-8d1151823def\n", + "hello world\n" + ] + } + ], + "source": [ + "import { RunnableConfig, RunnableLambda } from \"@langchain/core/runnables\";\n", + "import { dispatchCustomEvent as dispatchCustomEventWeb } from \"@langchain/core/callbacks/dispatch/web\";\n", + "\n", + "const reflect = RunnableLambda.from(async (value: string, config?: RunnableConfig) => {\n", + " await dispatchCustomEventWeb(\"event1\", { reversed: value.split(\"\").reverse().join(\"\") }, config);\n", + " await dispatchCustomEventWeb(\"event2\", 5, config);\n", + " return value;\n", + "});\n", + "\n", + "await reflect.invoke(\"hello world\", {\n", + " callbacks: [{\n", + " handleCustomEvent(eventName, data, runId) {\n", + " console.log(eventName, data, runId);\n", + " },\n", + " }]\n", + "});" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Related\n", + "\n", + "You've now seen how to emit custom events from within your chains.\n", + "\n", + "You can check out the more in depth guide for [stream events](/docs/how_to/streaming/#using-stream-events) for more ways to parse and receive intermediate steps from your chains." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "TypeScript", + "language": "typescript", + "name": "tslab" + }, + "language_info": { + "codemirror_mode": { + "mode": "typescript", + "name": "javascript", + "typescript": true + }, + "file_extension": ".ts", + "mimetype": "text/typescript", + "name": "typescript", + "version": "3.7.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 0808271517a2890171e0325a91a0b3180ee2b26a Mon Sep 17 00:00:00 2001 From: jacoblee93 Date: Tue, 16 Jul 2024 11:45:41 -0700 Subject: [PATCH 2/4] Typos --- .../docs/how_to/callbacks_custom_events.ipynb | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/core_docs/docs/how_to/callbacks_custom_events.ipynb b/docs/core_docs/docs/how_to/callbacks_custom_events.ipynb index 7a3e9e626f15..47f12d751392 100644 --- a/docs/core_docs/docs/how_to/callbacks_custom_events.ipynb +++ b/docs/core_docs/docs/how_to/callbacks_custom_events.ipynb @@ -32,15 +32,15 @@ "\n", ":::info\n", "- Custom callback events can only be dispatched from within an existing `Runnable`.\n", - "- If using `streamEvents`, you must use `version: \"v2\"` to see custom events.\n", - "- Sending or rendering custom callbacks events in LangSmith is not yet supported.\n", + "- If using `streamEvents`, you must use `version: \"v2\"` to consume custom events.\n", + "- Sending or rendering custom callback events in LangSmith is not yet supported.\n", ":::\n", "\n", "## Stream Events API\n", "\n", "The most useful way to consume custom events is via the [`.streamEvents()`](/docs/concepts/#astream_events) method.\n", "\n", - "We can use the `dispatchCustomEvent` API to emit custom events in an async setting. \n", + "We can use the `dispatchCustomEvent` API to emit custom events from this method. \n", "\n", ":::caution Compatibility\n", "Dispatching custom callback events requires `@langchain/core>=0.2.16`. See [this guide](/docs/how_to/installation/#installing-integration-packages) for some considerations to take when upgrading `@langchain/core`.\n", @@ -156,33 +156,33 @@ "source": [ "## Callback Handler\n", "\n", - "Let's see how to emit custom events in a sync environment with `dispatchCustomEvent`.\n", + "Let's see how to emit custom events with `dispatchCustomEvent`.\n", "\n", "Remember, you **must** call `dispatchCustomEvent` from within an existing `Runnable`." ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "event1 { reversed: 'dlrow olleh' } 5f45eb5f-39df-4c78-aa36-8d1151823def\n", - "event2 5 5f45eb5f-39df-4c78-aa36-8d1151823def\n", + "event1 { reversed: 'dlrow olleh' } 9c3770ac-c83d-4626-9643-b5fd80eb5431\n", + "event2 5 9c3770ac-c83d-4626-9643-b5fd80eb5431\n", "hello world\n" ] } ], "source": [ "import { RunnableConfig, RunnableLambda } from \"@langchain/core/runnables\";\n", - "import { dispatchCustomEvent as dispatchCustomEventWeb } from \"@langchain/core/callbacks/dispatch/web\";\n", + "import { dispatchCustomEvent } from \"@langchain/core/callbacks/dispatch\";\n", "\n", - "const reflect = RunnableLambda.from(async (value: string, config?: RunnableConfig) => {\n", - " await dispatchCustomEventWeb(\"event1\", { reversed: value.split(\"\").reverse().join(\"\") }, config);\n", - " await dispatchCustomEventWeb(\"event2\", 5, config);\n", + "const reflect = RunnableLambda.from(async (value: string) => {\n", + " await dispatchCustomEvent(\"event1\", { reversed: value.split(\"\").reverse().join(\"\") });\n", + " await dispatchCustomEvent(\"event2\", 5);\n", " return value;\n", "});\n", "\n", From 224d95f0283f5586e46d175e6e7b2d81de39948a Mon Sep 17 00:00:00 2001 From: jacoblee93 Date: Tue, 16 Jul 2024 11:46:34 -0700 Subject: [PATCH 3/4] Typing --- docs/core_docs/docs/how_to/callbacks_custom_events.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/core_docs/docs/how_to/callbacks_custom_events.ipynb b/docs/core_docs/docs/how_to/callbacks_custom_events.ipynb index 47f12d751392..27e43a2bf046 100644 --- a/docs/core_docs/docs/how_to/callbacks_custom_events.ipynb +++ b/docs/core_docs/docs/how_to/callbacks_custom_events.ipynb @@ -26,8 +26,8 @@ "\n", "| Attribute | Type | Description |\n", "|-----------|------|----------------------------------------------------------------------------------------------------------|\n", - "| name | str | A user defined name for the event. |\n", - "| data | Any | The data associated with the event. This can be anything, though we suggest making it JSON serializable. |\n", + "| name | string | A user defined name for the event. |\n", + "| data | any | The data associated with the event. This can be anything, though we suggest making it JSON serializable. |\n", "\n", "\n", ":::info\n", From 044aa6a8a1a19a9baf05a8502572c2fd425944c5 Mon Sep 17 00:00:00 2001 From: jacoblee93 Date: Tue, 16 Jul 2024 11:47:03 -0700 Subject: [PATCH 4/4] Fix link --- docs/core_docs/docs/how_to/callbacks_custom_events.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core_docs/docs/how_to/callbacks_custom_events.ipynb b/docs/core_docs/docs/how_to/callbacks_custom_events.ipynb index 27e43a2bf046..b910ce083248 100644 --- a/docs/core_docs/docs/how_to/callbacks_custom_events.ipynb +++ b/docs/core_docs/docs/how_to/callbacks_custom_events.ipynb @@ -38,7 +38,7 @@ "\n", "## Stream Events API\n", "\n", - "The most useful way to consume custom events is via the [`.streamEvents()`](/docs/concepts/#astream_events) method.\n", + "The most useful way to consume custom events is via the [`.streamEvents()`](/docs/concepts/#streamevents) method.\n", "\n", "We can use the `dispatchCustomEvent` API to emit custom events from this method. \n", "\n",