The fact this is the case for two different ways of attempting to handle tool calling leads me to believe there is a separate issue here.
[0:tasks] Starting step 0 with 1 task:
- __start__ -> {'messages': [HumanMessage(content="Fetch the UK's GDP over the past 5 years, then draw a line graph of it. Once you code it up, finish.")]}
[0:writes] Finished step 0 with writes to 1 channel:
- messages -> [HumanMessage(content="Fetch the UK's GDP over the past 5 years, then draw a line graph of it. Once you code it up, finish.")]
[1:tasks] Starting step 1 with 1 task:
- Researcher -> {'messages': [HumanMessage(content="Fetch the UK's GDP over the past 5 years, then draw a line graph of it. Once you code it up, finish.")],
'sender': None}
{'Researcher': {'messages': [AIMessage(content='Okay, let\'s get started on fetching the UK\'s GDP data for the past 5 years and drawing a line graph.\n\n<function_calls>\n<invoke>\n<tool_name>python_repl</tool_name>\n<parameters>\n<code>\nimport requests\nimport json\nfrom datetime import datetime, timedelta\n\n# Function to fetch GDP data for the UK from the past 5 years\ndef fetch_uk_gdp_data():\n url = "https://ec.europa.eu/eurostat/wdds/rest/data/v2.1/json/en/naida_10_gdp"\n params = {\n "na_item": "B1GQ",\n "s_adj": "SNA_SAM",\n "precision": "1",\n "unit": "CP_MEUR",\n "geo": "UK",\n "startPeriod": (datetime.now() - timedelta(days=365*5)).strftime("%Y"),\n "endPeriod": datetime.now().year\n }\n response = requests.get(url, params=params)\n data = json.loads(response.text)\n \n gdp_data = []\n for value in data["value"]["orderedValue"]:\n year = int(value["period"])\n gdp = float(value["value"])\n gdp_data.append((year, gdp))\n \n return gdp_data\n\n# Fetch and print the GDP data\nuk_gdp_data = fetch_uk_gdp_data()\nprint("UK GDP data for the past 5 years:")\nfor year, gdp in uk_gdp_data:\n print(f"{year}: {gdp:.2f} billion Euros")\n</code>\n</parameters>\n</invoke>\n</function_calls>\n\nThe code above fetches the UK\'s GDP data for the past 5 years from the Eurostat API and prints it out.\n\nTo draw a line graph, we can use a plotting library like matplotlib:\n\n<function_calls>\n<invoke>\n<tool_name>python_repl</tool_name>\n<parameters>\n<code>\nimport matplotlib.pyplot as plt\n\n# Fetch GDP data if not already fetched\nif \'uk_gdp_data\' not in locals():\n uk_gdp_data = fetch_uk_gdp_data()\n\n# Extract years and GDP values from data\nyears, gdp_values = zip(*uk_gdp_data)\n\n# Create line plot\nplt.figure(figsize=(8, 6))\nplt.plot(years, gdp_values)\nplt.title("UK GDP for the Past 5 Years")\nplt.xlabel("Year")\nplt.ylabel("GDP (billion Euros)")\nplt.xticks(years)\nplt.show()\n</code>\n</parameters>\n</invoke>\n</function_calls>\n\nThis code will generate a line graph showing the UK\'s GDP over the past 5 years, with the years on the x-axis and the GDP values on the y-axis.\n\nFINAL ANSWER: The code above fetches the UK\'s GDP data for the past 5 years from the Eurostat API, prints out the data, and generates a line graph visualizing the GDP values over time using matplotlib.', additional_kwargs={'usage': {'prompt_tokens': 381, 'completion_tokens': 775, 'total_tokens': 1156}, 'stop_reason': 'tool_use', 'tool_calls': [{'name': 'python_repl', 'args': {}, 'id': 'call_MEMWS5G7T1iOyTFHj5S6gg'}, {'name': 'python_repl', 'args': {}, 'id': 'call_jevlNPPIT_2oxzHFx8U_oA'}], 'model_id': 'anthropic.claude-3-sonnet-20240229-v1:0'}, response_metadata={'usage': {'prompt_tokens': 381, 'completion_tokens': 775, 'total_tokens': 1156}, 'stop_reason': 'tool_use', 'tool_calls': [{'name': 'python_repl', 'args': {}, 'id': 'call_MEMWS5G7T1iOyTFHj5S6gg'}, {'name': 'python_repl', 'args': {}, 'id': 'call_jevlNPPIT_2oxzHFx8U_oA'}], 'model_id': 'anthropic.claude-3-sonnet-20240229-v1:0'}, name='Researcher', id='run-6b95de2b-a61e-4bfe-a5f1-7bc11405fe02-0', tool_calls=[{'name': 'python_repl', 'args': {}, 'id': 'call_MEMWS5G7T1iOyTFHj5S6gg'}, {'name': 'python_repl', 'args': {}, 'id': 'call_jevlNPPIT_2oxzHFx8U_oA'}])], 'sender': 'Researcher'}}
----
[1:writes] Finished step 1 with writes to 2 channels:
- messages -> [AIMessage(content='Okay, let\'s get started on fetching the UK\'s GDP data for the past 5 years and drawing a line graph.\n\n<function_calls>\n<invoke>\n<tool_name>python_repl</tool_name>\n<parameters>\n<code>\nimport requests\nimport json\nfrom datetime import datetime, timedelta\n\n# Function to fetch GDP data for the UK from the past 5 years\ndef fetch_uk_gdp_data():\n url = "https://ec.europa.eu/eurostat/wdds/rest/data/v2.1/json/en/naida_10_gdp"\n params = {\n "na_item": "B1GQ",\n "s_adj": "SNA_SAM",\n "precision": "1",\n "unit": "CP_MEUR",\n "geo": "UK",\n "startPeriod": (datetime.now() - timedelta(days=365*5)).strftime("%Y"),\n "endPeriod": datetime.now().year\n }\n response = requests.get(url, params=params)\n data = json.loads(response.text)\n \n gdp_data = []\n for value in data["value"]["orderedValue"]:\n year = int(value["period"])\n gdp = float(value["value"])\n gdp_data.append((year, gdp))\n \n return gdp_data\n\n# Fetch and print the GDP data\nuk_gdp_data = fetch_uk_gdp_data()\nprint("UK GDP data for the past 5 years:")\nfor year, gdp in uk_gdp_data:\n print(f"{year}: {gdp:.2f} billion Euros")\n</code>\n</parameters>\n</invoke>\n</function_calls>\n\nThe code above fetches the UK\'s GDP data for the past 5 years from the Eurostat API and prints it out.\n\nTo draw a line graph, we can use a plotting library like matplotlib:\n\n<function_calls>\n<invoke>\n<tool_name>python_repl</tool_name>\n<parameters>\n<code>\nimport matplotlib.pyplot as plt\n\n# Fetch GDP data if not already fetched\nif \'uk_gdp_data\' not in locals():\n uk_gdp_data = fetch_uk_gdp_data()\n\n# Extract years and GDP values from data\nyears, gdp_values = zip(*uk_gdp_data)\n\n# Create line plot\nplt.figure(figsize=(8, 6))\nplt.plot(years, gdp_values)\nplt.title("UK GDP for the Past 5 Years")\nplt.xlabel("Year")\nplt.ylabel("GDP (billion Euros)")\nplt.xticks(years)\nplt.show()\n</code>\n</parameters>\n</invoke>\n</function_calls>\n\nThis code will generate a line graph showing the UK\'s GDP over the past 5 years, with the years on the x-axis and the GDP values on the y-axis.\n\nFINAL ANSWER: The code above fetches the UK\'s GDP data for the past 5 years from the Eurostat API, prints out the data, and generates a line graph visualizing the GDP values over time using matplotlib.', additional_kwargs={'usage': {'prompt_tokens': 381, 'completion_tokens': 775, 'total_tokens': 1156}, 'stop_reason': 'tool_use', 'tool_calls': [{'name': 'python_repl', 'args': {}, 'id': 'call_MEMWS5G7T1iOyTFHj5S6gg'}, {'name': 'python_repl', 'args': {}, 'id': 'call_jevlNPPIT_2oxzHFx8U_oA'}], 'model_id': 'anthropic.claude-3-sonnet-20240229-v1:0'}, response_metadata={'usage': {'prompt_tokens': 381, 'completion_tokens': 775, 'total_tokens': 1156}, 'stop_reason': 'tool_use', 'tool_calls': [{'name': 'python_repl', 'args': {}, 'id': 'call_MEMWS5G7T1iOyTFHj5S6gg'}, {'name': 'python_repl', 'args': {}, 'id': 'call_jevlNPPIT_2oxzHFx8U_oA'}], 'model_id': 'anthropic.claude-3-sonnet-20240229-v1:0'}, name='Researcher', id='run-6b95de2b-a61e-4bfe-a5f1-7bc11405fe02-0', tool_calls=[{'name': 'python_repl', 'args': {}, 'id': 'call_MEMWS5G7T1iOyTFHj5S6gg'}, {'name': 'python_repl', 'args': {}, 'id': 'call_jevlNPPIT_2oxzHFx8U_oA'}])]
- sender -> 'Researcher'
[2:tasks] Starting step 2 with 1 task:
- call_tool -> {'messages': [HumanMessage(content="Fetch the UK's GDP over the past 5 years, then draw a line graph of it. Once you code it up, finish."),
AIMessage(content='Okay, let\'s get started on fetching the UK\'s GDP data for the past 5 years and drawing a line graph.\n\n<function_calls>\n<invoke>\n<tool_name>python_repl</tool_name>\n<parameters>\n<code>\nimport requests\nimport json\nfrom datetime import datetime, timedelta\n\n# Function to fetch GDP data for the UK from the past 5 years\ndef fetch_uk_gdp_data():\n url = "https://ec.europa.eu/eurostat/wdds/rest/data/v2.1/json/en/naida_10_gdp"\n params = {\n "na_item": "B1GQ",\n "s_adj": "SNA_SAM",\n "precision": "1",\n "unit": "CP_MEUR",\n "geo": "UK",\n "startPeriod": (datetime.now() - timedelta(days=365*5)).strftime("%Y"),\n "endPeriod": datetime.now().year\n }\n response = requests.get(url, params=params)\n data = json.loads(response.text)\n \n gdp_data = []\n for value in data["value"]["orderedValue"]:\n year = int(value["period"])\n gdp = float(value["value"])\n gdp_data.append((year, gdp))\n \n return gdp_data\n\n# Fetch and print the GDP data\nuk_gdp_data = fetch_uk_gdp_data()\nprint("UK GDP data for the past 5 years:")\nfor year, gdp in uk_gdp_data:\n print(f"{year}: {gdp:.2f} billion Euros")\n</code>\n</parameters>\n</invoke>\n</function_calls>\n\nThe code above fetches the UK\'s GDP data for the past 5 years from the Eurostat API and prints it out.\n\nTo draw a line graph, we can use a plotting library like matplotlib:\n\n<function_calls>\n<invoke>\n<tool_name>python_repl</tool_name>\n<parameters>\n<code>\nimport matplotlib.pyplot as plt\n\n# Fetch GDP data if not already fetched\nif \'uk_gdp_data\' not in locals():\n uk_gdp_data = fetch_uk_gdp_data()\n\n# Extract years and GDP values from data\nyears, gdp_values = zip(*uk_gdp_data)\n\n# Create line plot\nplt.figure(figsize=(8, 6))\nplt.plot(years, gdp_values)\nplt.title("UK GDP for the Past 5 Years")\nplt.xlabel("Year")\nplt.ylabel("GDP (billion Euros)")\nplt.xticks(years)\nplt.show()\n</code>\n</parameters>\n</invoke>\n</function_calls>\n\nThis code will generate a line graph showing the UK\'s GDP over the past 5 years, with the years on the x-axis and the GDP values on the y-axis.\n\nFINAL ANSWER: The code above fetches the UK\'s GDP data for the past 5 years from the Eurostat API, prints out the data, and generates a line graph visualizing the GDP values over time using matplotlib.', additional_kwargs={'usage': {'prompt_tokens': 381, 'completion_tokens': 775, 'total_tokens': 1156}, 'stop_reason': 'tool_use', 'tool_calls': [{'name': 'python_repl', 'args': {}, 'id': 'call_MEMWS5G7T1iOyTFHj5S6gg'}, {'name': 'python_repl', 'args': {}, 'id': 'call_jevlNPPIT_2oxzHFx8U_oA'}], 'model_id': 'anthropic.claude-3-sonnet-20240229-v1:0'}, response_metadata={'usage': {'prompt_tokens': 381, 'completion_tokens': 775, 'total_tokens': 1156}, 'stop_reason': 'tool_use', 'tool_calls': [{'name': 'python_repl', 'args': {}, 'id': 'call_MEMWS5G7T1iOyTFHj5S6gg'}, {'name': 'python_repl', 'args': {}, 'id': 'call_jevlNPPIT_2oxzHFx8U_oA'}], 'model_id': 'anthropic.claude-3-sonnet-20240229-v1:0'}, name='Researcher', id='run-6b95de2b-a61e-4bfe-a5f1-7bc11405fe02-0', tool_calls=[{'name': 'python_repl', 'args': {}, 'id': 'call_MEMWS5G7T1iOyTFHj5S6gg'}, {'name': 'python_repl', 'args': {}, 'id': 'call_jevlNPPIT_2oxzHFx8U_oA'}])],
'sender': 'Researcher'}
---------------------------------------------------------------------------
ValidationError Traceback (most recent call last)
Cell In[22], line 14
1 events = graph.stream(
2 {
3 "messages": [
(...)
12 {"recursion_limit": 150},
13 )
---> 14 for s in events:
15 print(s)
16 print("----")
File ~/Documents/Projects/jupyter/.venv/lib/python3.10/site-packages/langgraph/pregel/__init__.py:963, in Pregel.stream(self, input, config, stream_mode, output_keys, input_keys, interrupt_before, interrupt_after, debug)
960 del fut, task
962 # panic on failure or timeout
--> 963 _panic_or_proceed(done, inflight, step)
964 # don't keep futures around in memory longer than needed
965 del done, inflight, futures
File ~/Documents/Projects/jupyter/.venv/lib/python3.10/site-packages/langgraph/pregel/__init__.py:1489, in _panic_or_proceed(done, inflight, step)
1487 inflight.pop().cancel()
1488 # raise the exception
-> 1489 raise exc
1491 if inflight:
1492 # if we got here means we timed out
1493 while inflight:
1494 # cancel all pending tasks
File [/usr/lib/python3.10/concurrent/futures/thread.py:58](http://localhost:8888/usr/lib/python3.10/concurrent/futures/thread.py#line=57), in _WorkItem.run(self)
55 return
57 try:
---> 58 result = self.fn(*self.args, **self.kwargs)
59 except BaseException as exc:
60 self.future.set_exception(exc)
File ~/Documents/Projects/jupyter/.venv/lib/python3.10/site-packages/langgraph/pregel/retry.py:66, in run_with_retry(task, retry_policy)
64 task.writes.clear()
65 # run the task
---> 66 task.proc.invoke(task.input, task.config)
67 # if successful, end
68 break
File ~/Documents/Projects/jupyter/.venv/lib/python3.10/site-packages/langchain_core/runnables/base.py:2493, in RunnableSequence.invoke(self, input, config, **kwargs)
2489 config = patch_config(
2490 config, callbacks=run_manager.get_child(f"seq:step:{i+1}")
2491 )
2492 if i == 0:
-> 2493 input = step.invoke(input, config, **kwargs)
2494 else:
2495 input = step.invoke(input, config)
File ~/Documents/Projects/jupyter/.venv/lib/python3.10/site-packages/langgraph/utils.py:95, in RunnableCallable.invoke(self, input, config, **kwargs)
93 if accepts_config(self.func):
94 kwargs["config"] = config
---> 95 ret = context.run(self.func, input, **kwargs)
96 if isinstance(ret, Runnable) and self.recurse:
97 return ret.invoke(input, config)
File ~/Documents/Projects/jupyter/.venv/lib/python3.10/site-packages/langgraph/prebuilt/tool_node.py:68, in ToolNode._func(self, input, config)
63 return ToolMessage(
64 content=str_output(output), name=call["name"], tool_call_id=call["id"]
65 )
67 with get_executor_for_config(config) as executor:
---> 68 outputs = [*executor.map(run_one, message.tool_calls)]
69 if output_type == "list":
70 return outputs
File [/usr/lib/python3.10/concurrent/futures/_base.py:621](http://localhost:8888/usr/lib/python3.10/concurrent/futures/_base.py#line=620), in Executor.map.<locals>.result_iterator()
618 while fs:
619 # Careful not to keep a reference to the popped future
620 if timeout is None:
--> 621 yield _result_or_cancel(fs.pop())
622 else:
623 yield _result_or_cancel(fs.pop(), end_time - time.monotonic())
File [/usr/lib/python3.10/concurrent/futures/_base.py:319](http://localhost:8888/usr/lib/python3.10/concurrent/futures/_base.py#line=318), in _result_or_cancel(***failed resolving arguments***)
317 try:
318 try:
--> 319 return fut.result(timeout)
320 finally:
321 fut.cancel()
File [/usr/lib/python3.10/concurrent/futures/_base.py:451](http://localhost:8888/usr/lib/python3.10/concurrent/futures/_base.py#line=450), in Future.result(self, timeout)
449 raise CancelledError()
450 elif self._state == FINISHED:
--> 451 return self.__get_result()
453 self._condition.wait(timeout)
455 if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:
File [/usr/lib/python3.10/concurrent/futures/_base.py:403](http://localhost:8888/usr/lib/python3.10/concurrent/futures/_base.py#line=402), in Future.__get_result(self)
401 if self._exception:
402 try:
--> 403 raise self._exception
404 finally:
405 # Break a reference cycle with the exception in self._exception
406 self = None
File [/usr/lib/python3.10/concurrent/futures/thread.py:58](http://localhost:8888/usr/lib/python3.10/concurrent/futures/thread.py#line=57), in _WorkItem.run(self)
55 return
57 try:
---> 58 result = self.fn(*self.args, **self.kwargs)
59 except BaseException as exc:
60 self.future.set_exception(exc)
File ~/Documents/Projects/jupyter/.venv/lib/python3.10/site-packages/langchain_core/runnables/config.py:499, in ContextThreadPoolExecutor.map.<locals>._wrapped_fn(*args)
498 def _wrapped_fn(*args: Any) -> T:
--> 499 return contexts.pop().run(fn, *args)
File ~/Documents/Projects/jupyter/.venv/lib/python3.10/site-packages/langgraph/prebuilt/tool_node.py:62, in ToolNode._func.<locals>.run_one(call)
61 def run_one(call: ToolCall):
---> 62 output = self.tools_by_name[call["name"]].invoke(call["args"], config)
63 return ToolMessage(
64 content=str_output(output), name=call["name"], tool_call_id=call["id"]
65 )
File ~/Documents/Projects/jupyter/.venv/lib/python3.10/site-packages/langchain_core/tools.py:260, in BaseTool.invoke(self, input, config, **kwargs)
253 def invoke(
254 self,
255 input: Union[str, Dict],
256 config: Optional[RunnableConfig] = None,
257 **kwargs: Any,
258 ) -> Any:
259 config = ensure_config(config)
--> 260 return self.run(
261 input,
262 callbacks=config.get("callbacks"),
263 tags=config.get("tags"),
264 metadata=config.get("metadata"),
265 run_name=config.get("run_name"),
266 run_id=config.pop("run_id", None),
267 config=config,
268 **kwargs,
269 )
File ~/Documents/Projects/jupyter/.venv/lib/python3.10/site-packages/langchain_core/tools.py:417, in BaseTool.run(self, tool_input, verbose, start_color, color, callbacks, tags, metadata, run_name, run_id, config, **kwargs)
415 except ValidationError as e:
416 if not self.handle_validation_error:
--> 417 raise e
418 elif isinstance(self.handle_validation_error, bool):
419 observation = "Tool input validation error"
File ~/Documents/Projects/jupyter/.venv/lib/python3.10/site-packages/langchain_core/tools.py:406, in BaseTool.run(self, tool_input, verbose, start_color, color, callbacks, tags, metadata, run_name, run_id, config, **kwargs)
404 context = copy_context()
405 context.run(_set_config_context, child_config)
--> 406 parsed_input = self._parse_input(tool_input)
407 tool_args, tool_kwargs = self._to_args_and_kwargs(parsed_input)
408 observation = (
409 context.run(
410 self._run, *tool_args, run_manager=run_manager, **tool_kwargs
(...)
413 else context.run(self._run, *tool_args, **tool_kwargs)
414 )
File ~/Documents/Projects/jupyter/.venv/lib/python3.10/site-packages/langchain_core/tools.py:304, in BaseTool._parse_input(self, tool_input)
302 else:
303 if input_args is not None:
--> 304 result = input_args.parse_obj(tool_input)
305 return {
306 k: getattr(result, k)
307 for k, v in result.dict().items()
308 if k in tool_input
309 }
310 return tool_input
File ~/Documents/Projects/jupyter/.venv/lib/python3.10/site-packages/pydantic/v1/main.py:526, in BaseModel.parse_obj(cls, obj)
524 exc = TypeError(f'{cls.__name__} expected dict not {obj.__class__.__name__}')
525 raise ValidationError([ErrorWrapper(exc, loc=ROOT_KEY)], cls) from e
--> 526 return cls(**obj)
File ~/Documents/Projects/jupyter/.venv/lib/python3.10/site-packages/pydantic/v1/main.py:341, in BaseModel.__init__(__pydantic_self__, **data)
339 values, fields_set, validation_error = validate_model(__pydantic_self__.__class__, data)
340 if validation_error:
--> 341 raise validation_error
342 try:
343 object_setattr(__pydantic_self__, '__dict__', values)
ValidationError: 1 validation error for python_replSchema
code
field required (type=value_error.missing)