mirror of
https://github.com/langchain-ai/langgraph-example.git
synced 2026-07-01 16:12:43 -04:00
656 lines
23 KiB
Plaintext
656 lines
23 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "51466c8d-8ce4-4b3d-be4e-18fdbeda5f53",
|
|
"metadata": {},
|
|
"source": [
|
|
"# How to have a human in the loop\n",
|
|
"\n",
|
|
"With it's built in persistence layer, LangGraph API is perfect for human-in-the-loop workflows.\n",
|
|
"Here we cover a few such examples:\n",
|
|
"\n",
|
|
"1. Having a human in the loop to approve a tool call\n",
|
|
"2. Having a human in the loop to edit a tool call\n",
|
|
"3. Having a human in the loop to edit an old state and resume execution from there\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "521d975b-e94b-4c37-bfa1-82d969e2a4dc",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from langgraph_sdk import get_client"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"id": "27a1392b-86c3-464e-99a8-90ffc965f3ec",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"client = get_client()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"id": "230c0464-a6e5-420f-9e38-ca514e5634ce",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"{'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca',\n",
|
|
" 'graph_id': 'agent',\n",
|
|
" 'config': {},\n",
|
|
" 'created_at': '2024-05-18T00:19:39.688822+00:00',\n",
|
|
" 'updated_at': '2024-05-18T00:19:39.688822+00:00',\n",
|
|
" 'metadata': {'created_by': 'system'}}"
|
|
]
|
|
},
|
|
"execution_count": 4,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"assistant_id = \"agent\""
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "e0209129-239b-452e-a59a-47be716bbf8c",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Approve a tool call"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"id": "56aa5159-5583-4134-9210-709b969bda6f",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"{'thread_id': '54ed0901-6767-46c9-a5f9-b65c1c5fd89c',\n",
|
|
" 'created_at': '2024-05-18T22:46:16.724701+00:00',\n",
|
|
" 'updated_at': '2024-05-18T22:46:16.724701+00:00',\n",
|
|
" 'metadata': {}}"
|
|
]
|
|
},
|
|
"execution_count": 5,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"thread = await client.threads.create()\n",
|
|
"thread"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"id": "147c3f98-f889-4f05-a090-6b31f2a0b291",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"[]"
|
|
]
|
|
},
|
|
"execution_count": 6,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"runs = await client.runs.list(thread['thread_id'])\n",
|
|
"runs"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "77dae6ad-bb7b-468d-b7fd-9b8a35f13ccb",
|
|
"metadata": {},
|
|
"source": [
|
|
"We now want to add a human-in-the-loop step before a tool is called.\n",
|
|
"We can do this by adding `interrupt_before=[\"action\"]`, which tells us to interrupt before calling the action node.\n",
|
|
"We can do this either when compiling the graph or when kicking off a run.\n",
|
|
"Here we will do it when kicking of a run."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"id": "7da70e20-1a4e-4df2-b996-1927f474c835",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Receiving new event of type: metadata...\n",
|
|
"{'run_id': '3b77ef83-687a-4840-8858-0371f91a92c3'}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Receiving new event of type: data...\n",
|
|
"{'agent': {'messages': [{'content': [{'id': 'toolu_01HwZqM1ptX6E15A5LAmyZTB', 'input': {'query': 'weather in san francisco'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}], 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-e5d17791-4d37-4ad2-815f-a0c4cba62585', 'example': False, 'tool_calls': [{'name': 'tavily_search_results_json', 'args': {'query': 'weather in san francisco'}, 'id': 'toolu_01HwZqM1ptX6E15A5LAmyZTB'}], 'invalid_tool_calls': []}]}}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Receiving new event of type: end...\n",
|
|
"None\n",
|
|
"\n",
|
|
"\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"input = {\"messages\": [{\"role\": \"human\", \"content\": \"whats the weather in sf\"}]}\n",
|
|
"async for chunk in client.runs.stream(\n",
|
|
" thread['thread_id'], assistant_id, input=input, stream_mode=\"updates\", interrupt_before=['action']\n",
|
|
"):\n",
|
|
" print(f\"Receiving new event of type: {chunk.event}...\")\n",
|
|
" print(chunk.data)\n",
|
|
" print(\"\\n\\n\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "a36ac0d6-7843-4fab-909c-0b5b6e725a7f",
|
|
"metadata": {},
|
|
"source": [
|
|
"We can now kick off a new run on the same thread with `None` as the input in order to just continue the existing thread."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"id": "bded66c7-b56e-4db5-809f-fa5a31d8a012",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Receiving new event of type: metadata...\n",
|
|
"{'run_id': 'a46f733d-cf5b-4ee3-9e07-08612468c8df'}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Receiving new event of type: data...\n",
|
|
"{'action': {'messages': [{'content': '[{\"url\": \"https://www.weatherapi.com/\", \"content\": \"{\\'location\\': {\\'name\\': \\'San Francisco\\', \\'region\\': \\'California\\', \\'country\\': \\'United States of America\\', \\'lat\\': 37.78, \\'lon\\': -122.42, \\'tz_id\\': \\'America/Los_Angeles\\', \\'localtime_epoch\\': 1716072201, \\'localtime\\': \\'2024-05-18 15:43\\'}, \\'current\\': {\\'last_updated_epoch\\': 1716071400, \\'last_updated\\': \\'2024-05-18 15:30\\', \\'temp_c\\': 18.9, \\'temp_f\\': 66.0, \\'is_day\\': 1, \\'condition\\': {\\'text\\': \\'Partly cloudy\\', \\'icon\\': \\'//cdn.weatherapi.com/weather/64x64/day/116.png\\', \\'code\\': 1003}, \\'wind_mph\\': 18.6, \\'wind_kph\\': 29.9, \\'wind_degree\\': 280, \\'wind_dir\\': \\'W\\', \\'pressure_mb\\': 1015.0, \\'pressure_in\\': 29.96, \\'precip_mm\\': 0.0, \\'precip_in\\': 0.0, \\'humidity\\': 59, \\'cloud\\': 25, \\'feelslike_c\\': 18.9, \\'feelslike_f\\': 66.0, \\'vis_km\\': 16.0, \\'vis_miles\\': 9.0, \\'uv\\': 5.0, \\'gust_mph\\': 23.0, \\'gust_kph\\': 37.1}}\"}]', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': 'tavily_search_results_json', 'id': '8be98ff3-6d61-41c5-8384-8db6b7abdbfb', 'tool_call_id': 'toolu_01HwZqM1ptX6E15A5LAmyZTB'}]}}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Receiving new event of type: data...\n",
|
|
"{'agent': {'messages': [{'content': \"The weather in San Francisco is currently partly cloudy with a temperature of around 66°F (18.9°C). There are westerly winds of 18.6 mph (29.9 km/h) with gusts up to 23 mph (37.1 km/h). The humidity is 59% and visibility is good at 9 miles (16 km). UV levels are moderate at 5.0.\\n\\nIn summary, it's a nice partly cloudy spring day in San Francisco with comfortable temperatures and a moderate breeze. The weather conditions seem ideal for being outdoors and enjoying the city.\", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-7a8a2ff8-d0d6-4200-b0a5-926f2b6a4798', 'example': False, 'tool_calls': [], 'invalid_tool_calls': []}]}}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Receiving new event of type: end...\n",
|
|
"None\n",
|
|
"\n",
|
|
"\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"input = None\n",
|
|
"async for chunk in client.runs.stream(\n",
|
|
" thread['thread_id'], assistant_id, input=input, stream_mode=\"updates\", interrupt_before=['action']\n",
|
|
"):\n",
|
|
" print(f\"Receiving new event of type: {chunk.event}...\")\n",
|
|
" print(chunk.data)\n",
|
|
" print(\"\\n\\n\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "2072ce5a-8771-42f9-b2de-5d3a7a9c817b",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Edit a tool call\n",
|
|
"\n",
|
|
"What if we want to edit the tool call?\n",
|
|
"We can also do that.\n",
|
|
"Let's kick off another run, with the same `interrupt_before=['action']`"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"id": "b226b687-02da-4eef-9286-46dba92b17ba",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Receiving new event of type: metadata...\n",
|
|
"{'run_id': 'c7c8e313-dad9-47d9-bd03-e112c94eff9e'}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Receiving new event of type: data...\n",
|
|
"{'agent': {'messages': [{'content': [{'id': 'toolu_01NGhKmeciaT7TfhBSwUT3mi', 'input': {'query': 'weather in los angeles'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}], 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-3d417aa5-e9c1-4b76-90f8-597519c28af9', 'example': False, 'tool_calls': [{'name': 'tavily_search_results_json', 'args': {'query': 'weather in los angeles'}, 'id': 'toolu_01NGhKmeciaT7TfhBSwUT3mi'}], 'invalid_tool_calls': []}]}}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Receiving new event of type: end...\n",
|
|
"None\n",
|
|
"\n",
|
|
"\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"input = {\"messages\": [{\"role\": \"human\", \"content\": \"whats the weather in la?\"}]}\n",
|
|
"async for chunk in client.runs.stream(\n",
|
|
" thread['thread_id'], assistant_id, input=input, stream_mode=\"updates\", interrupt_before=['action']\n",
|
|
"):\n",
|
|
" print(f\"Receiving new event of type: {chunk.event}...\")\n",
|
|
" print(chunk.data)\n",
|
|
" print(\"\\n\\n\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "ab338423-c18d-446c-9aa3-3ad2f16d742a",
|
|
"metadata": {},
|
|
"source": [
|
|
"We can now inspect the state of the thread"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"id": "bd9ca1f4-c3b0-4fa3-8c91-233a9129a142",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"thread_state = await client.threads.get_state(thread['thread_id'])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "31e82414-afd2-46c4-a605-ce3eb46df485",
|
|
"metadata": {},
|
|
"source": [
|
|
"Let's get the last message of the thread - this is the one we want to update"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 11,
|
|
"id": "fe832ec1-7ae0-4d11-8408-d4da88d4dced",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"last_message = thread_state['values']['messages'][-1]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 12,
|
|
"id": "434253fe-7397-45e2-8be8-91d002088a96",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"[{'id': 'toolu_01NGhKmeciaT7TfhBSwUT3mi',\n",
|
|
" 'input': {'query': 'weather in los angeles'},\n",
|
|
" 'name': 'tavily_search_results_json',\n",
|
|
" 'type': 'tool_use'}]"
|
|
]
|
|
},
|
|
"execution_count": 12,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"last_message['content']"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "6d007b31-c8a2-465c-bc78-a5909ca7931c",
|
|
"metadata": {},
|
|
"source": [
|
|
"Let's now modify the tool call to say Louisiana"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 13,
|
|
"id": "55fcb316-450b-4b8c-9ae9-e7ee395acc55",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"last_message['tool_calls'] = [{\n",
|
|
" 'id': last_message['tool_calls'][0]['id'],\n",
|
|
" 'name': 'tavily_search_results_json',\n",
|
|
" # We change the query to say temperature\n",
|
|
" 'args': {'query': 'weather in Louisiana'}\n",
|
|
"}]\n",
|
|
"# last_message['content'] = [{\n",
|
|
"# 'id': last_message['content'][0]['id'],\n",
|
|
"# 'name': 'tavily_search_results_json',\n",
|
|
"# # We change the query to say temperature\n",
|
|
"# 'input': {'query': 'weather in Louisiana'},\n",
|
|
"# 'type': 'tool_use'\n",
|
|
"# }]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "d49be54e-5334-47be-8dfb-78b8a8155e98",
|
|
"metadata": {},
|
|
"source": [
|
|
"We can now update the state - we only need to pass in the last updated message because our graph will handle the update."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 14,
|
|
"id": "0438f997-bad3-48f6-b532-9ac3a95263c2",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"{'configurable': {'thread_id': '54ed0901-6767-46c9-a5f9-b65c1c5fd89c',\n",
|
|
" 'thread_ts': '1ef15688-1dbd-68f5-8007-75dc0e110124'}}"
|
|
]
|
|
},
|
|
"execution_count": 14,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"await client.threads.update_state(thread['thread_id'], values={\"messages\": [last_message]})"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "c96668ab-80fa-4ae6-a90b-773a943ba331",
|
|
"metadata": {},
|
|
"source": [
|
|
"Let's now check the state of the thread again, and in particular the final message"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 15,
|
|
"id": "31936711-4af4-4bd1-ac10-9ce52922dd2f",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"[{'name': 'tavily_search_results_json',\n",
|
|
" 'args': {'query': 'weather in Louisiana'},\n",
|
|
" 'id': 'toolu_01NGhKmeciaT7TfhBSwUT3mi'}]"
|
|
]
|
|
},
|
|
"execution_count": 15,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"thread_state = await client.threads.get_state(thread['thread_id'])\n",
|
|
"thread_state['values']['messages'][-1]['tool_calls']"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "20aa8ff3-7876-4db2-9333-c5396cd637ac",
|
|
"metadata": {},
|
|
"source": [
|
|
"Great! We changed it. If we now resume execution (by kicking off a new run with null inputs on the same thread) it should use that new tool call."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 16,
|
|
"id": "8e2c4eeb-2888-4979-9877-aa4a53dec5ea",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Receiving new event of type: metadata...\n",
|
|
"{'run_id': '1a1ebed1-3581-418a-81be-e834b40c5c82'}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Receiving new event of type: data...\n",
|
|
"{'action': {'messages': [{'content': '[{\"url\": \"https://www.weatherapi.com/\", \"content\": \"{\\'location\\': {\\'name\\': \\'Louisiana\\', \\'region\\': \\'Missouri\\', \\'country\\': \\'USA United States of America\\', \\'lat\\': 39.44, \\'lon\\': -91.06, \\'tz_id\\': \\'America/Chicago\\', \\'localtime_epoch\\': 1716072393, \\'localtime\\': \\'2024-05-18 17:46\\'}, \\'current\\': {\\'last_updated_epoch\\': 1716072300, \\'last_updated\\': \\'2024-05-18 17:45\\', \\'temp_c\\': 29.0, \\'temp_f\\': 84.2, \\'is_day\\': 1, \\'condition\\': {\\'text\\': \\'Partly cloudy\\', \\'icon\\': \\'//cdn.weatherapi.com/weather/64x64/day/116.png\\', \\'code\\': 1003}, \\'wind_mph\\': 6.9, \\'wind_kph\\': 11.2, \\'wind_degree\\': 220, \\'wind_dir\\': \\'SW\\', \\'pressure_mb\\': 1011.0, \\'pressure_in\\': 29.86, \\'precip_mm\\': 0.0, \\'precip_in\\': 0.0, \\'humidity\\': 46, \\'cloud\\': 50, \\'feelslike_c\\': 31.4, \\'feelslike_f\\': 88.6, \\'vis_km\\': 16.0, \\'vis_miles\\': 9.0, \\'uv\\': 7.0, \\'gust_mph\\': 7.4, \\'gust_kph\\': 11.9}}\"}]', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': 'tavily_search_results_json', 'id': '728f8ac9-729e-4bf7-b560-b332a73c8f47', 'tool_call_id': 'toolu_01NGhKmeciaT7TfhBSwUT3mi'}]}}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Receiving new event of type: data...\n",
|
|
"{'agent': {'messages': [{'content': [{'text': 'The search results seem to be for the weather in Louisiana, Missouri rather than Los Angeles, California. Let me try the search again:', 'type': 'text'}, {'id': 'toolu_019YAXWMK33tG9DaxMzrowc8', 'input': {'query': 'weather in los angeles california'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}], 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-c42a3b14-2611-4a1d-8907-95dcdb18f07f', 'example': False, 'tool_calls': [{'name': 'tavily_search_results_json', 'args': {'query': 'weather in los angeles california'}, 'id': 'toolu_019YAXWMK33tG9DaxMzrowc8'}], 'invalid_tool_calls': []}]}}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Receiving new event of type: end...\n",
|
|
"None\n",
|
|
"\n",
|
|
"\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"input = None\n",
|
|
"async for chunk in client.runs.stream(\n",
|
|
" thread['thread_id'], assistant_id, input=input, stream_mode=\"updates\", interrupt_before=['action']\n",
|
|
"):\n",
|
|
" print(f\"Receiving new event of type: {chunk.event}...\")\n",
|
|
" print(chunk.data)\n",
|
|
" print(\"\\n\\n\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "065f8165-43d8-4876-86af-0cfffd712fee",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Edit an old state\n",
|
|
"\n",
|
|
"Let's now imagine we want to go back in time and edit the tool call after we had already made it.\n",
|
|
"In order to do this, we can get first get the full history of the thread."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 46,
|
|
"id": "de050efd-73a4-441e-91e0-18e08f773a42",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"thread_history = await client.threads.get_history(thread['thread_id'], limit=100)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 47,
|
|
"id": "07e15435-4a5f-4c2a-b748-0e0f7ab02a28",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"11"
|
|
]
|
|
},
|
|
"execution_count": 47,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"len(thread_history)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "a292e721-36c4-41b8-85e4-378f0770652a",
|
|
"metadata": {},
|
|
"source": [
|
|
"After that, we can get the correct state we want to be in. The 0th index state is the most recent one, while the -1 index state is the first.\n",
|
|
"In this case, we want to go to the state where the last message had the tool calls for `weather in los angeles`"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 48,
|
|
"id": "132d207c-11cb-4efb-a330-88ebdfc612c8",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"[{'name': 'tavily_search_results_json',\n",
|
|
" 'args': {'query': 'weather in los angeles'},\n",
|
|
" 'id': 'toolu_01FnuDKhUfagwoqhNfiTYTfS'}]"
|
|
]
|
|
},
|
|
"execution_count": 48,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"rewind_state = thread_history[3]\n",
|
|
"rewind_state['values']['messages'][-1]['tool_calls']"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 49,
|
|
"id": "45e01ddf-2ccf-4029-b431-e5fce2235b59",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"{'configurable': {'thread_id': 'df85453d-cb86-48c8-ae84-12081faa1bdf',\n",
|
|
" 'thread_ts': '1ef15582-3442-6db7-8006-9166bbb0e80f'}}"
|
|
]
|
|
},
|
|
"execution_count": 49,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"rewind_state['config']"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "d229468e-2f94-4b29-b56b-1d402554dcfb",
|
|
"metadata": {},
|
|
"source": [
|
|
"If we want to, we can now resume execution from that place in time"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 50,
|
|
"id": "94ebc63e-f2cf-4da1-bc8d-52c4731ab0c6",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Receiving new event of type: metadata...\n",
|
|
"{'run_id': 'a1cc9263-ef0a-4c04-9194-6f01624d0ef0'}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Receiving new event of type: data...\n",
|
|
"{'action': {'messages': [{'content': '[{\"url\": \"https://www.weatherapi.com/\", \"content\": \"{\\'location\\': {\\'name\\': \\'Los Angeles\\', \\'region\\': \\'California\\', \\'country\\': \\'United States of America\\', \\'lat\\': 34.05, \\'lon\\': -118.24, \\'tz_id\\': \\'America/Los_Angeles\\', \\'localtime_epoch\\': 1716071728, \\'localtime\\': \\'2024-05-18 15:35\\'}, \\'current\\': {\\'last_updated_epoch\\': 1716071400, \\'last_updated\\': \\'2024-05-18 15:30\\', \\'temp_c\\': 20.0, \\'temp_f\\': 68.0, \\'is_day\\': 1, \\'condition\\': {\\'text\\': \\'Partly cloudy\\', \\'icon\\': \\'//cdn.weatherapi.com/weather/64x64/day/116.png\\', \\'code\\': 1003}, \\'wind_mph\\': 2.2, \\'wind_kph\\': 3.6, \\'wind_degree\\': 226, \\'wind_dir\\': \\'SW\\', \\'pressure_mb\\': 1016.0, \\'pressure_in\\': 29.99, \\'precip_mm\\': 0.0, \\'precip_in\\': 0.0, \\'humidity\\': 61, \\'cloud\\': 50, \\'feelslike_c\\': 20.0, \\'feelslike_f\\': 68.0, \\'vis_km\\': 16.0, \\'vis_miles\\': 9.0, \\'uv\\': 6.0, \\'gust_mph\\': 12.6, \\'gust_kph\\': 20.3}}\"}]', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': 'tavily_search_results_json', 'id': '7137b2e5-566b-418b-b642-b3c6b64c5224', 'tool_call_id': 'toolu_01FnuDKhUfagwoqhNfiTYTfS'}]}}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Receiving new event of type: data...\n",
|
|
"{'agent': {'messages': [{'content': 'The search results show the current weather conditions in Los Angeles. As of 3:30pm on May 18, 2024, the weather in Los Angeles is partly cloudy with a temperature around 68°F (20°C). Winds are light from the southwest around 2-3 mph. The humidity is 61% and visibility is good at 9 miles. Overall, it appears to be a nice spring day in LA with partly sunny skies and comfortable temperatures in the upper 60s.', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-3966b68a-c381-4933-a852-e6a4697c962c', 'example': False, 'tool_calls': [], 'invalid_tool_calls': []}]}}\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Receiving new event of type: end...\n",
|
|
"None\n",
|
|
"\n",
|
|
"\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"input = None\n",
|
|
"async for chunk in client.runs.stream(\n",
|
|
" thread['thread_id'], \n",
|
|
" assistant_id, \n",
|
|
" input=input, \n",
|
|
" stream_mode=\"updates\", \n",
|
|
" interrupt_before=['action'],\n",
|
|
" config=rewind_state['config']\n",
|
|
"):\n",
|
|
" print(f\"Receiving new event of type: {chunk.event}...\")\n",
|
|
" print(chunk.data)\n",
|
|
" print(\"\\n\\n\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "492f1d37-0979-4210-8dd7-bc70cdc308f3",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": []
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3 (ipykernel)",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.11.9"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|