Files
langgraph/examples/cloud_examples/langgraph_to_langgraph_cloud.ipynb
T

42 KiB

How to convert LangGraph calls to LangGraph Cloud calls

So you're used to interacting with your graph locally, but now you've deployed it with LangGraph cloud. How do you change all the places in your codebase where you call LangGraph directly to call LangGraph Cloud? This notebook contains side-by-side comparisons so you can easily transition from calling LangGraph to calling LangGraph Cloud.

Setup

We'll be using a simple ReAct agent for this how-to guide. You will also need to set up a project with agent.py and langgraph.json files. See quick start for setting this up.

In [1]:
%%capture --no-stderr
%pip install -U langgraph langchain-openai
In [2]:
import getpass
import os


def _set_env(var: str):
    if not os.environ.get(var):
        os.environ[var] = getpass.getpass(f"{var}: ")


_set_env("OPENAI_API_KEY")
OPENAI_API_KEY:  ········
In [3]:
# this is all that's needed for the agent.py
from typing import Literal
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.runnables import ConfigurableField
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent


@tool
def get_weather(city: Literal["nyc", "sf"]):
    """Use this to get weather information."""
    if city == "nyc":
        return "It might be cloudy in nyc"
    elif city == "sf":
        return "It's always sunny in sf"
    else:
        raise AssertionError("Unknown city")


tools = [get_weather]

model = ChatOpenAI(model_name="gpt-4o", temperature=0)
graph = create_react_agent(model, tools)

Now we'll set up the langgraph client. The client assumes the LangGraph Cloud server is running on localhost:8123

In [4]:
from langgraph_sdk import get_client

client = get_client()

Invoking the graph

Below examples show how to mirror .invoke() / .ainvoke() methods of LangGraph's CompiledGraph runnable, i.e. create a blocking graph execution

With LangGraph

In [5]:
inputs = {"messages": [("human", "what's the weather in sf")]}
invoke_output = await graph.ainvoke(inputs)
In [6]:
for m in invoke_output["messages"]:
    m.pretty_print()
================================ Human Message =================================

what's the weather in sf
================================== Ai Message ==================================
Tool Calls:
  get_weather (call_GOKlsBY2XKm7pZnmAzJweYDU)
 Call ID: call_GOKlsBY2XKm7pZnmAzJweYDU
  Args:
    city: sf
================================= Tool Message =================================
Name: get_weather

It's always sunny in sf
================================== Ai Message ==================================

The weather in San Francisco is currently sunny.

With LangGraph Cloud

In [7]:
# NOTE: We're not specifying the thread here -- this allows us to create a thread just for this run
wait_output = await client.runs.wait(None, "agent", input=inputs)
In [8]:
# we'll use this for pretty message formatting
from langchain_core.messages import convert_to_messages
In [9]:
for m in convert_to_messages(wait_output["messages"]):
    m.pretty_print()
================================ Human Message =================================

what's the weather in sf
================================== Ai Message ==================================
Tool Calls:
  get_weather (call_pQJsT9uLG3nVppN8Dt2OhnFx)
 Call ID: call_pQJsT9uLG3nVppN8Dt2OhnFx
  Args:
    city: sf
================================= Tool Message =================================
Name: get_weather

It's always sunny in sf
================================== Ai Message ==================================

The weather in San Francisco is currently sunny.

Streaming

Below examples show how to mirror .stream() / .astream() methods for streaming partial graph execution results.
Note: LangGraph's stream_mode=values/updates/debug behave nearly identically in LangGraph Cloud (with the exception of additional streamed chunks with metadata / end events types)

With LangGraph

In [10]:
inputs = {"messages": [("human", "what's the weather in sf")]}
async for chunk in graph.astream(inputs, stream_mode="values"):
    chunk["messages"][-1].pretty_print()
================================ Human Message =================================

what's the weather in sf
================================== Ai Message ==================================
Tool Calls:
  get_weather (call_302y9671bqMkMcpLZOWLNAnq)
 Call ID: call_302y9671bqMkMcpLZOWLNAnq
  Args:
    city: sf
================================= Tool Message =================================
Name: get_weather

It's always sunny in sf
================================== Ai Message ==================================

The weather in San Francisco is currently sunny.

With LangGraph Cloud

In [11]:
inputs = {"messages": [("human", "what's the weather in sf")]}
async for chunk in client.runs.stream(
    None, "agent", input=inputs, stream_mode="values"
):
    if chunk.event == "values":
        messages = convert_to_messages(chunk.data["messages"])
        messages[-1].pretty_print()
================================ Human Message =================================

what's the weather in sf
================================== Ai Message ==================================
Tool Calls:
  get_weather (call_NYVNSiBeF0oTAYnaDrlEAG7a)
 Call ID: call_NYVNSiBeF0oTAYnaDrlEAG7a
  Args:
    city: sf
================================= Tool Message =================================
Name: get_weather

It's always sunny in sf
================================== Ai Message ==================================

The weather in San Francisco is currently sunny.

Persistence

In LangGraph, you need to provide a checkpointer object when compiling your graph to persist state across interactions with your graph (i.e. threads). In LangGraph Cloud, you don't need to create a checkpointer -- the server already implements one for you. You can also directly manage the threads from a client.

With LangGraph

In [12]:
from langgraph.checkpoint.memory import MemorySaver
In [13]:
checkpointer = MemorySaver()
graph_with_memory = create_react_agent(model, tools, checkpointer=checkpointer)
In [14]:
inputs = {"messages": [("human", "what's the weather in nyc")]}
invoke_output = await graph_with_memory.ainvoke(
    inputs, config={"configurable": {"thread_id": "1"}}
)
invoke_output["messages"][-1].pretty_print()
================================== Ai Message ==================================

The weather in NYC might be cloudy.
In [15]:
inputs = {"messages": [("human", "what's it known for?")]}
invoke_output = await graph_with_memory.ainvoke(
    inputs, config={"configurable": {"thread_id": "1"}}
)
invoke_output["messages"][-1].pretty_print()
================================== Ai Message ==================================

New York City (NYC) is known for a variety of iconic landmarks, cultural institutions, and vibrant neighborhoods. Some of the most notable things NYC is known for include:

1. **Statue of Liberty**: A symbol of freedom and democracy.
2. **Times Square**: Famous for its bright lights, Broadway theaters, and bustling atmosphere.
3. **Central Park**: A large urban park offering a green oasis in the middle of the city.
4. **Empire State Building**: An iconic skyscraper with an observation deck offering panoramic views of the city.
5. **Broadway**: Renowned for its world-class theater productions.
6. **Wall Street**: The financial hub of the United States.
7. **Museums**: Including the Metropolitan Museum of Art, the Museum of Modern Art (MoMA), and the American Museum of Natural History.
8. **Diverse Cuisine**: A melting pot of culinary experiences from around the world.
9. **Cultural Diversity**: A rich tapestry of cultures, languages, and traditions.
10. **Fashion**: A global fashion capital, home to numerous designers and fashion events.

These are just a few highlights, but NYC offers countless other attractions and experiences.
In [16]:
inputs = {"messages": [("human", "what's it known for?")]}
invoke_output = await graph_with_memory.ainvoke(
    inputs, config={"configurable": {"thread_id": "2"}}
)
invoke_output["messages"][-1].pretty_print()
================================== Ai Message ==================================

Could you please specify what "it" refers to? Are you asking about a specific city, person, object, or something else?
In [17]:
# get the state of the thread
checkpointer.get({"configurable": {"thread_id": "2"}})
Out [17]:
{'v': 1,
 'ts': '2024-06-22T02:31:49.722569+00:00',
 'id': '1ef303f9-4149-6b56-8001-a80d1e3c9dc6',
 'channel_values': {'messages': [HumanMessage(content="what's it known for?", id='ea0d1672-05e9-4d77-9dff-b33bd5c824e7'),
   AIMessage(content='Could you please specify what "it" refers to? Are you asking about a specific city, person, object, or something else?', response_metadata={'token_usage': {'completion_tokens': 28, 'prompt_tokens': 57, 'total_tokens': 85}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_3e7d703517', 'finish_reason': 'stop', 'logprobs': None}, id='run-f0381dc0-d891-4203-8f77-3155ba17998c-0', usage_metadata={'input_tokens': 57, 'output_tokens': 28, 'total_tokens': 85})],
  'agent': 'agent'},
 'channel_versions': {'__start__': 2,
  'messages': 3,
  'start:agent': 3,
  'agent': 3},
 'versions_seen': {'__start__': {'__start__': 1},
  'agent': {'start:agent': 2},
  'tools': {}},
 'pending_sends': []}

With LangGraph Cloud

Let's now reproduce the same using LangGraph Cloud. Note that instead of using a checkpointer we just create a new thread on the backend and pass the ID to the API

In [18]:
thread = await client.threads.create()
In [19]:
inputs = {"messages": [("human", "what's the weather in nyc")]}
wait_output = await client.runs.wait(thread["thread_id"], "agent", input=inputs)
convert_to_messages(wait_output["messages"])[-1].pretty_print()
================================== Ai Message ==================================

The weather in NYC might be cloudy.
In [20]:
inputs = {"messages": [("human", "what's it known for?")]}
wait_output = await client.runs.wait(thread["thread_id"], "agent", input=inputs)
convert_to_messages(wait_output["messages"])[-1].pretty_print()
================================== Ai Message ==================================

New York City (NYC) is known for a variety of iconic landmarks, cultural institutions, and vibrant neighborhoods. Some of the most notable features include:

1. **Statue of Liberty**: A symbol of freedom and democracy.
2. **Times Square**: Known for its bright lights, Broadway theaters, and bustling atmosphere.
3. **Central Park**: A large urban park offering a natural retreat in the middle of the city.
4. **Empire State Building**: An iconic skyscraper with an observation deck offering panoramic views of the city.
5. **Broadway**: Famous for its world-class theater productions.
6. **Wall Street**: The financial hub of the United States.
7. **Museums**: Including the Metropolitan Museum of Art, the Museum of Modern Art (MoMA), and the American Museum of Natural History.
8. **Diverse Cuisine**: A melting pot of culinary experiences from around the world.
9. **Cultural Diversity**: A rich tapestry of cultures, languages, and traditions.
10. **Fashion**: A global fashion capital, home to New York Fashion Week.

These are just a few highlights of what makes NYC a unique and vibrant city.
In [21]:
thread = await client.threads.create()
In [22]:
inputs = {"messages": [("human", "what's it known for?")]}
wait_output = await client.runs.wait(thread["thread_id"], "agent", input=inputs)
convert_to_messages(wait_output["messages"])[-1].pretty_print()
================================== Ai Message ==================================

Could you please specify what "it" refers to? Are you asking about a specific city, person, object, or something else?
In [23]:
# get the state of the thread
await client.threads.get_state(thread["thread_id"])
Out [23]:
{'values': {'messages': [{'content': "what's it known for?",
    'additional_kwargs': {},
    'response_metadata': {},
    'type': 'human',
    'name': None,
    'id': 'b62078f1-7c44-4a0e-b7b0-05e475ae3188',
    'example': False},
   {'content': 'Could you please specify what "it" refers to? Are you asking about a specific city, person, object, or something else?',
    'additional_kwargs': {},
    'response_metadata': {'finish_reason': 'stop'},
    'type': 'ai',
    'name': None,
    'id': 'run-502c6cf3-d584-4e31-98a6-5e59f1d2a72f',
    'example': False,
    'tool_calls': [],
    'invalid_tool_calls': [],
    'usage_metadata': None}]},
 'next': [],
 'config': {'configurable': {'thread_id': 'fcff410c-9adb-416f-a7ce-09b230afcac9',
   'thread_ts': '1ef303f9-7d8e-6d0a-8001-2b4ce14235da'}},
 'metadata': {'step': 1,
  'run_id': '1ef303f9-73e6-6c6b-b407-39938d3dfd7e',
  'source': 'loop',
  'writes': {'agent': {'messages': [{'id': 'run-502c6cf3-d584-4e31-98a6-5e59f1d2a72f',
      'name': None,
      'type': 'ai',
      'content': 'Could you please specify what "it" refers to? Are you asking about a specific city, person, object, or something else?',
      'example': False,
      'tool_calls': [],
      'usage_metadata': None,
      'additional_kwargs': {},
      'response_metadata': {'finish_reason': 'stop'},
      'invalid_tool_calls': []}]}},
  'user_id': '',
  'graph_id': 'agent',
  'thread_id': 'fcff410c-9adb-416f-a7ce-09b230afcac9',
  'created_by': 'system',
  'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'},
 'created_at': '2024-06-22T02:31:56.042330+00:00',
 'parent_config': {'configurable': {'thread_id': 'fcff410c-9adb-416f-a7ce-09b230afcac9',
   'thread_ts': '1ef303f9-7400-6e2c-8000-e8d5075bfa2a'}}}

Breakpoints

With LangGraph

In [24]:
inputs = {"messages": [("human", "what's the weather in sf")]}
async for chunk in graph_with_memory.astream(
    inputs,
    stream_mode="values",
    interrupt_before=["tools"],
    config={"configurable": {"thread_id": "3"}},
):
    chunk["messages"][-1].pretty_print()
================================ Human Message =================================

what's the weather in sf
================================== Ai Message ==================================
Tool Calls:
  get_weather (call_cYp3BijeW2JNQ9RqJRdkrbMu)
 Call ID: call_cYp3BijeW2JNQ9RqJRdkrbMu
  Args:
    city: sf
In [25]:
async for chunk in graph_with_memory.astream(
    None,
    stream_mode="values",
    interrupt_before=["tools"],
    config={"configurable": {"thread_id": "3"}},
):
    chunk["messages"][-1].pretty_print()
================================= Tool Message =================================
Name: get_weather

It's always sunny in sf
================================== Ai Message ==================================

The weather in San Francisco is sunny!

With LangGraph Cloud

Similar to the persistence example, we need to create a thread so we can persist state and continue from the breakpoint.

In [26]:
thread = await client.threads.create()

async for chunk in client.runs.stream(
    thread["thread_id"],
    "agent",
    input=inputs,
    stream_mode="values",
    interrupt_before=["tools"],
):
    if chunk.event == "values":
        messages = convert_to_messages(chunk.data["messages"])
        messages[-1].pretty_print()
================================ Human Message =================================

what's the weather in sf
================================== Ai Message ==================================
Tool Calls:
  get_weather (call_MVQEJtPYAj1nJ7J6YaCeLX8a)
 Call ID: call_MVQEJtPYAj1nJ7J6YaCeLX8a
  Args:
    city: sf
In [27]:
async for chunk in client.runs.stream(
    thread["thread_id"],
    "agent",
    input=None,
    stream_mode="values",
    interrupt_before=["tools"],
):
    if chunk.event == "values":
        messages = convert_to_messages(chunk.data["messages"])
        messages[-1].pretty_print()
================================= Tool Message =================================
Name: get_weather

It's always sunny in sf
================================== Ai Message ==================================

The weather in San Francisco is currently sunny.

Steaming events

For streaming events, in LangGraph you need to use .astream_events method on the CompiledGraph. In LangGraph Cloud this is done via passing stream_mode="events"

With LangGraph

In [28]:
inputs = {"messages": [("human", "what's the weather in sf")]}
async for chunk in graph.astream_events(inputs, version="v2"):
    if chunk["event"] == "on_chat_model_stream":
        chunk["data"]["chunk"].pretty_print()
/Users/vadymbarda/.virtualenvs/langgraph-example-dev/lib/python3.11/site-packages/langchain_core/_api/beta_decorator.py:87: LangChainBetaWarning: This API is in beta and may change in the future.
  warn_beta(
============================ Aimessagechunk Message ============================
Invalid Tool Calls:
  get_weather (call_dsr61w9qcahi8CC7LV2S29O3)
 Call ID: call_dsr61w9qcahi8CC7LV2S29O3
  Args:
============================ Aimessagechunk Message ============================
Tool Calls:
   (None)
 Call ID: None
  Args:
============================ Aimessagechunk Message ============================
Invalid Tool Calls:
  None (None)
 Call ID: None
  Args:
    city
============================ Aimessagechunk Message ============================
Invalid Tool Calls:
  None (None)
 Call ID: None
  Args:
    ":"
============================ Aimessagechunk Message ============================
Invalid Tool Calls:
  None (None)
 Call ID: None
  Args:
    sf
============================ Aimessagechunk Message ============================
Invalid Tool Calls:
  None (None)
 Call ID: None
  Args:
    "}
============================ Aimessagechunk Message ============================
============================ Aimessagechunk Message ============================
============================ Aimessagechunk Message ============================

The
============================ Aimessagechunk Message ============================

 weather
============================ Aimessagechunk Message ============================

 in
============================ Aimessagechunk Message ============================

 San
============================ Aimessagechunk Message ============================

 Francisco
============================ Aimessagechunk Message ============================

 is
============================ Aimessagechunk Message ============================

 currently
============================ Aimessagechunk Message ============================

 sunny
============================ Aimessagechunk Message ============================

.
============================ Aimessagechunk Message ============================

 Enjoy
============================ Aimessagechunk Message ============================

 the
============================ Aimessagechunk Message ============================

 sunshine
============================ Aimessagechunk Message ============================

!
============================ Aimessagechunk Message ============================

With LangGraph Clound

In [32]:
inputs = {"messages": [("human", "what's the weather in sf")]}
async for chunk in client.runs.stream(
    None, "agent", input=inputs, stream_mode="events"
):
    if chunk.event == "events" and chunk.data["event"] == "on_chat_model_stream":
        print(chunk.data["data"]["chunk"])
{'content': '', 'additional_kwargs': {'tool_calls': [{'index': 0, 'id': 'call_JYWaAecaAV92cOlZwRHi9B7M', 'function': {'arguments': '', 'name': 'get_weather'}, 'type': 'function'}]}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-855fec3d-15df-4ae8-b74d-208a0e463be9', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [{'name': 'get_weather', 'args': '', 'id': 'call_JYWaAecaAV92cOlZwRHi9B7M', 'error': None}], 'usage_metadata': None, 'tool_call_chunks': [{'name': 'get_weather', 'args': '', 'id': 'call_JYWaAecaAV92cOlZwRHi9B7M', 'index': 0}]}
{'content': '', 'additional_kwargs': {'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': '{"', 'name': None}, 'type': None}]}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-855fec3d-15df-4ae8-b74d-208a0e463be9', 'example': False, 'tool_calls': [{'name': '', 'args': {}, 'id': None}], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': '{"', 'id': None, 'index': 0}]}
{'content': '', 'additional_kwargs': {'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': 'city', 'name': None}, 'type': None}]}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-855fec3d-15df-4ae8-b74d-208a0e463be9', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [{'name': None, 'args': 'city', 'id': None, 'error': None}], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': 'city', 'id': None, 'index': 0}]}
{'content': '', 'additional_kwargs': {'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': '":"', 'name': None}, 'type': None}]}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-855fec3d-15df-4ae8-b74d-208a0e463be9', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [{'name': None, 'args': '":"', 'id': None, 'error': None}], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': '":"', 'id': None, 'index': 0}]}
{'content': '', 'additional_kwargs': {'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': 'sf', 'name': None}, 'type': None}]}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-855fec3d-15df-4ae8-b74d-208a0e463be9', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [{'name': None, 'args': 'sf', 'id': None, 'error': None}], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': 'sf', 'id': None, 'index': 0}]}
{'content': '', 'additional_kwargs': {'tool_calls': [{'index': 0, 'id': None, 'function': {'arguments': '"}', 'name': None}, 'type': None}]}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-855fec3d-15df-4ae8-b74d-208a0e463be9', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [{'name': None, 'args': '"}', 'id': None, 'error': None}], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': '"}', 'id': None, 'index': 0}]}
{'content': '', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'tool_calls'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-855fec3d-15df-4ae8-b74d-208a0e463be9', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}
{'content': '', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}
{'content': 'The', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}
{'content': ' weather', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}
{'content': ' in', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}
{'content': ' San', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}
{'content': ' Francisco', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}
{'content': ' is', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}
{'content': ' currently', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}
{'content': ' sunny', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}
{'content': '.', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}
{'content': ' Enjoy', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}
{'content': ' the', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}
{'content': ' sunshine', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}
{'content': '!', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}
{'content': '', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-19a0bdff-8724-4730-8052-c3ac89525461', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}