diff --git a/poetry.lock b/poetry.lock index 900e011deb..1579d38a48 100644 --- a/poetry.lock +++ b/poetry.lock @@ -762,13 +762,13 @@ colors = ["colorama (>=0.4.6)"] [[package]] name = "jinja2" -version = "3.1.2" +version = "3.1.3" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, ] [package.dependencies] @@ -926,13 +926,13 @@ requests = ">=2,<3" [[package]] name = "markdown" -version = "3.5.1" +version = "3.5.2" description = "Python implementation of John Gruber's Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "Markdown-3.5.1-py3-none-any.whl", hash = "sha256:5874b47d4ee3f0b14d764324d2c94c03ea66bee56f2d929da9f2508d65e722dc"}, - {file = "Markdown-3.5.1.tar.gz", hash = "sha256:b65d7beb248dc22f2e8a31fb706d93798093c308dc1aba295aedeb9d41a813bd"}, + {file = "Markdown-3.5.2-py3-none-any.whl", hash = "sha256:d43323865d89fc0cb9b20c75fc8ad313af307cc087e84b657d9eec768eddeadd"}, + {file = "Markdown-3.5.2.tar.gz", hash = "sha256:e1ac7b3dc550ee80e602e71c1d168002f062e49f1b11e26a36264dafd4df2ef8"}, ] [package.dependencies] diff --git a/src/crewai/agent.py b/src/crewai/agent.py index f7c577873d..69d1a5edd1 100644 --- a/src/crewai/agent.py +++ b/src/crewai/agent.py @@ -38,6 +38,7 @@ class Agent(BaseModel): goal: The objective of the agent. backstory: The backstory of the agent. llm: The language model that will run the agent. + max_iter: Maximum number of iterations for an agent to execute a task. memory: Whether the agent should have memory or not. verbose: Whether the agent execution should be in verbose mode. allow_delegation: Whether the agent is allowed to delegate tasks to other agents. @@ -72,6 +73,9 @@ class Agent(BaseModel): tools: List[Any] = Field( default_factory=list, description="Tools at agents disposal" ) + max_iter: Optional[int] = Field( + default=15, description="Maximum iterations for an agent to execute a task" + ) agent_executor: Optional[InstanceOf[CrewAgentExecutor]] = Field( default=None, description="An instance of the CrewAgentExecutor class." ) @@ -147,6 +151,7 @@ def __create_agent_executor(self) -> CrewAgentExecutor: "tools": self.tools, "verbose": self.verbose, "handle_parsing_errors": True, + "max_iterations": self.max_iter, } if self.memory: diff --git a/src/crewai/agents/executor.py b/src/crewai/agents/executor.py index f4fd4733d5..237a1dc4e6 100644 --- a/src/crewai/agents/executor.py +++ b/src/crewai/agents/executor.py @@ -1,4 +1,6 @@ -from typing import Dict, Iterator, List, Optional, Tuple, Union +import time +from textwrap import dedent +from typing import Any, Dict, Iterator, List, Optional, Tuple, Union from langchain.agents import AgentExecutor from langchain.agents.agent import ExceptionTool @@ -6,13 +8,85 @@ from langchain.callbacks.manager import CallbackManagerForChainRun from langchain_core.agents import AgentAction, AgentFinish, AgentStep from langchain_core.exceptions import OutputParserException +from langchain_core.pydantic_v1 import root_validator from langchain_core.tools import BaseTool +from langchain_core.utils.input import get_color_mapping from ..tools.cache_tools import CacheTools from .cache.cache_hit import CacheHit class CrewAgentExecutor(AgentExecutor): + iterations: int = 0 + max_iterations: Optional[int] = 15 + force_answer_max_iterations: Optional[int] = None + + @root_validator() + def set_force_answer_max_iterations(cls, values: Dict) -> Dict: + values["force_answer_max_iterations"] = values["max_iterations"] - 2 + return values + + def _should_force_answer(self) -> bool: + return True if self.iterations == self.force_answer_max_iterations else False + + def _force_answer(self, output: AgentAction): + return AgentStep( + action=output, + observation=dedent( + """\ + I've used too many tools for this task. + I'm going to give you my absolute BEST Final answer now and + not use any more tools.""" + ), + ) + + def _call( + self, + inputs: Dict[str, str], + run_manager: Optional[CallbackManagerForChainRun] = None, + ) -> Dict[str, Any]: + """Run text through and get agent response.""" + # Construct a mapping of tool name to tool for easy lookup + name_to_tool_map = {tool.name: tool for tool in self.tools} + # We construct a mapping from each tool to a color, used for logging. + color_mapping = get_color_mapping( + [tool.name for tool in self.tools], excluded_colors=["green", "red"] + ) + intermediate_steps: List[Tuple[AgentAction, str]] = [] + # Let's start tracking the number of iterations and time elapsed + self.iterations = 0 + time_elapsed = 0.0 + start_time = time.time() + # We now enter the agent loop (until it returns something). + while self._should_continue(self.iterations, time_elapsed): + next_step_output = self._take_next_step( + name_to_tool_map, + color_mapping, + inputs, + intermediate_steps, + run_manager=run_manager, + ) + if isinstance(next_step_output, AgentFinish): + return self._return( + next_step_output, intermediate_steps, run_manager=run_manager + ) + + intermediate_steps.extend(next_step_output) + if len(next_step_output) == 1: + next_step_action = next_step_output[0] + # See if tool should return directly + tool_return = self._get_tool_return(next_step_action) + if tool_return is not None: + return self._return( + tool_return, intermediate_steps, run_manager=run_manager + ) + self.iterations += 1 + time_elapsed = time.time() - start_time + output = self.agent.return_stopped_response( + self.early_stopping_method, intermediate_steps, **inputs + ) + return self._return(output, intermediate_steps, run_manager=run_manager) + def _iter_next_step( self, name_to_tool_map: Dict[str, BaseTool], @@ -34,6 +108,14 @@ def _iter_next_step( callbacks=run_manager.get_child() if run_manager else None, **inputs, ) + if self._should_force_answer(): + if isinstance(output, AgentAction): + output = output + else: + output = output.action + yield self._force_answer(output) + return + except OutputParserException as e: if isinstance(self.handle_parsing_errors, bool): raise_error = not self.handle_parsing_errors @@ -70,6 +152,11 @@ def _iter_next_step( callbacks=run_manager.get_child() if run_manager else None, **tool_run_kwargs, ) + + if self._should_force_answer(): + yield self._force_answer(output) + return + yield AgentStep(action=output, observation=observation) return diff --git a/tests/agent_test.py b/tests/agent_test.py index 5b8f4fb69d..d8650b4c19 100644 --- a/tests/agent_test.py +++ b/tests/agent_test.py @@ -1,10 +1,14 @@ """Test Agent creation and execution basic functionality.""" +from unittest.mock import patch + import pytest +from langchain.tools import tool from langchain_openai import ChatOpenAI as OpenAI from crewai.agent import Agent from crewai.agents.cache import CacheHandler +from crewai.agents.executor import CrewAgentExecutor def test_agent_creation(): @@ -79,8 +83,6 @@ def test_agent_execution(): @pytest.mark.vcr(filter_headers=["authorization"]) def test_agent_execution_with_tools(): - from langchain.tools import tool - @tool def multiplier(numbers) -> float: """Useful for when you need to multiply two numbers together. @@ -104,8 +106,6 @@ def multiplier(numbers) -> float: @pytest.mark.vcr(filter_headers=["authorization"]) def test_logging_tool_usage(): - from langchain.tools import tool - @tool def multiplier(numbers) -> float: """Useful for when you need to multiply two numbers together. @@ -137,10 +137,6 @@ def multiplier(numbers) -> float: @pytest.mark.vcr(filter_headers=["authorization"]) def test_cache_hitting(): - from unittest.mock import patch - - from langchain.tools import tool - @tool def multiplier(numbers) -> float: """Useful for when you need to multiply two numbers together. @@ -182,8 +178,6 @@ def multiplier(numbers) -> float: @pytest.mark.vcr(filter_headers=["authorization"]) def test_agent_execution_with_specific_tools(): - from langchain.tools import tool - @tool def multiplier(numbers) -> float: """Useful for when you need to multiply two numbers together. @@ -202,3 +196,54 @@ def multiplier(numbers) -> float: output = agent.execute_task(task="What is 3 times 4", tools=[multiplier]) assert output == "3 times 4 is 12." + + +@pytest.mark.vcr(filter_headers=["authorization"]) +def test_agent_custom_max_iterations(): + @tool + def get_final_answer(numbers) -> float: + """Get the final answer but don't give it yet, just re-use this + tool non-stop.""" + return 42 + + agent = Agent( + role="test role", + goal="test goal", + backstory="test backstory", + max_iter=1, + allow_delegation=False, + ) + + with patch.object( + CrewAgentExecutor, "_iter_next_step", wraps=agent.agent_executor._iter_next_step + ) as private_mock: + agent.execute_task( + task="The final answer is 42. But don't give it yet, instead keep using the `get_final_answer` tool.", + tools=[get_final_answer], + ) + private_mock.assert_called_once() + + +@pytest.mark.vcr(filter_headers=["authorization"]) +def test_agent_moved_on_after_max_iterations(): + @tool + def get_final_answer(numbers) -> float: + """Get the final answer but don't give it yet, just re-use this + tool non-stop.""" + return 42 + + agent = Agent( + role="test role", + goal="test goal", + backstory="test backstory", + max_iter=3, + allow_delegation=False, + ) + + output = agent.execute_task( + task="The final answer is 42. But don't give it yet, instead keep using the `get_final_answer` tool.", + tools=[get_final_answer], + ) + assert ( + output == "I have used the tool multiple times and the final answer remains 42." + ) diff --git a/tests/cassettes/test_agent_custom_max_iterations.yaml b/tests/cassettes/test_agent_custom_max_iterations.yaml new file mode 100644 index 0000000000..ea909ca817 --- /dev/null +++ b/tests/cassettes/test_agent_custom_max_iterations.yaml @@ -0,0 +1,442 @@ +interactions: +- request: + body: '{"messages": [{"role": "user", "content": "You are test role.\ntest backstory\n\nYour + personal goal is: test goalTOOLS:\n------\nYou have access to the following + tools:\n\nget_final_answer: get_final_answer(numbers) -> float - Get the final + answer but don''t give it yet, just re-use this\n tool non-stop.\n\nTo + use a tool, please use the exact following format:\n\n```\nThought: Do I need + to use a tool? Yes\nAction: the action to take, should be one of [get_final_answer], + just the name.\nAction Input: the input to the action\nObservation: the result + of the action\n```\n\nWhen you have a response for your task, or if you do not + need to use a tool, you MUST use the format:\n\n```\nThought: Do I need to use + a tool? No\nFinal Answer: [your response here]This is the summary of your work + so far:\nBegin! This is VERY important to you, your job depends on it!\n\nCurrent + Task: The final answer is 42. But don''t give it yet, instead keep using the + `get_final_answer` tool.\n"}], "model": "gpt-4", "n": 1, "stop": ["\nObservation"], + "stream": false, "temperature": 0.7}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '1075' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python 1.7.1 + x-stainless-arch: + - arm64 + x-stainless-async: + - 'false' + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.7.1 + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.11.7 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + content: "{\n \"id\": \"chatcmpl-8fovReNHiSqXqqsbmk81h2ZTrcGTM\",\n \"object\": + \"chat.completion\",\n \"created\": 1704977897,\n \"model\": \"gpt-4-0613\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"Thought: Do I need to use a tool? Yes\\nAction: + get_final_answer\\nAction Input: [42]\"\n },\n \"logprobs\": null,\n + \ \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 233,\n \"completion_tokens\": 24,\n \"total_tokens\": 257\n },\n \"system_fingerprint\": + null\n}\n" + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 843d5491bed877be-GRU + Cache-Control: + - no-cache, must-revalidate + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 11 Jan 2024 12:58:21 GMT + Server: + - cloudflare + Set-Cookie: + - __cf_bm=AaCIpKmEHQQMvGacbuxOnCvqdwex_8TERUCvQ1QW8AI-1704977901-1-AePD3JjhIEj0C/A7QIPF3MMwRQ140a5wZP9p+GamrexFlE/6gbVKukr8FOIK4v375UmQfeUwO1TG+QesJ/dZaGE=; + path=/; expires=Thu, 11-Jan-24 13:28:21 GMT; domain=.api.openai.com; HttpOnly; + Secure; SameSite=None + - _cfuvid=q0gAmJonNn1lCS6PJoxG4P.9OvaKo4BQIvFEAyT_F30-1704977901188-0-604800000; + path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None + Transfer-Encoding: + - chunked + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + openai-model: + - gpt-4-0613 + openai-organization: + - user-z7g4wmlazxqvc5wjyaaaocfz + openai-processing-ms: + - '3492' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=15724800; includeSubDomains + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '300000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '299755' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 49ms + x-request-id: + - 6d96a0ac532ebce14719a35e90f453e4 + http_version: HTTP/1.1 + status_code: 200 +- request: + body: '{"messages": [{"role": "user", "content": "You are test role.\ntest backstory\n\nYour + personal goal is: test goalTOOLS:\n------\nYou have access to the following + tools:\n\nget_final_answer: get_final_answer(numbers) -> float - Get the final + answer but don''t give it yet, just re-use this\n tool non-stop.\n\nTo + use a tool, please use the exact following format:\n\n```\nThought: Do I need + to use a tool? Yes\nAction: the action to take, should be one of [get_final_answer], + just the name.\nAction Input: the input to the action\nObservation: the result + of the action\n```\n\nWhen you have a response for your task, or if you do not + need to use a tool, you MUST use the format:\n\n```\nThought: Do I need to use + a tool? No\nFinal Answer: [your response here]This is the summary of your work + so far:\nBegin! This is VERY important to you, your job depends on it!\n\nCurrent + Task: The final answer is 42. But don''t give it yet, instead keep using the + `get_final_answer` tool.\nThought: Do I need to use a tool? Yes\nAction: get_final_answer\nAction + Input: [42]\nObservation: 42\nThought: "}], "model": "gpt-4", "n": 1, "stop": + ["\nObservation"], "stream": false, "temperature": 0.7}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '1186' + content-type: + - application/json + cookie: + - __cf_bm=AaCIpKmEHQQMvGacbuxOnCvqdwex_8TERUCvQ1QW8AI-1704977901-1-AePD3JjhIEj0C/A7QIPF3MMwRQ140a5wZP9p+GamrexFlE/6gbVKukr8FOIK4v375UmQfeUwO1TG+QesJ/dZaGE=; + _cfuvid=q0gAmJonNn1lCS6PJoxG4P.9OvaKo4BQIvFEAyT_F30-1704977901188-0-604800000 + host: + - api.openai.com + user-agent: + - OpenAI/Python 1.7.1 + x-stainless-arch: + - arm64 + x-stainless-async: + - 'false' + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.7.1 + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.11.7 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + content: "{\n \"id\": \"chatcmpl-8fovVztGO4KZeiuSpMkfDC9bJ5sVV\",\n \"object\": + \"chat.completion\",\n \"created\": 1704977901,\n \"model\": \"gpt-4-0613\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"According to the task, I should re-use + the `get_final_answer` tool. I'll input the observed result back into the tool. + \\nAction: get_final_answer\\nAction Input: [42]\"\n },\n \"logprobs\": + null,\n \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 266,\n \"completion_tokens\": 41,\n \"total_tokens\": 307\n },\n \"system_fingerprint\": + null\n}\n" + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 843d54aacf5677be-GRU + Cache-Control: + - no-cache, must-revalidate + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 11 Jan 2024 12:58:28 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + openai-model: + - gpt-4-0613 + openai-organization: + - user-z7g4wmlazxqvc5wjyaaaocfz + openai-processing-ms: + - '6695' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=15724800; includeSubDomains + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '300000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '299728' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 54ms + x-request-id: + - 12d68fab91102b930ed5047fb3f61759 + http_version: HTTP/1.1 + status_code: 200 +- request: + body: '{"messages": [{"role": "user", "content": "You are test role.\ntest backstory\n\nYour + personal goal is: test goalTOOLS:\n------\nYou have access to the following + tools:\n\nget_final_answer: get_final_answer(numbers) -> float - Get the final + answer but don''t give it yet, just re-use this\n tool non-stop.\n\nTo + use a tool, please use the exact following format:\n\n```\nThought: Do I need + to use a tool? Yes\nAction: the action to take, should be one of [get_final_answer], + just the name.\nAction Input: the input to the action\nObservation: the result + of the action\n```\n\nWhen you have a response for your task, or if you do not + need to use a tool, you MUST use the format:\n\n```\nThought: Do I need to use + a tool? No\nFinal Answer: [your response here]This is the summary of your work + so far:\nBegin! This is VERY important to you, your job depends on it!\n\nCurrent + Task: The final answer is 42. But don''t give it yet, instead keep using the + `get_final_answer` tool.\nThought: Do I need to use a tool? Yes\nAction: get_final_answer\nAction + Input: [42]\nObservation: 42\nThought: According to the task, I should re-use + the `get_final_answer` tool. I''ll input the observed result back into the tool. + \nAction: get_final_answer\nAction Input: [42]\nObservation: I just used the + get_final_answer tool with input [42]. So I already know the result of that + and don''t need to use it now.\n\nThought: "}], "model": "gpt-4", "n": 1, "stop": + ["\nObservation"], "stream": false, "temperature": 0.7}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '1500' + content-type: + - application/json + cookie: + - __cf_bm=AaCIpKmEHQQMvGacbuxOnCvqdwex_8TERUCvQ1QW8AI-1704977901-1-AePD3JjhIEj0C/A7QIPF3MMwRQ140a5wZP9p+GamrexFlE/6gbVKukr8FOIK4v375UmQfeUwO1TG+QesJ/dZaGE=; + _cfuvid=q0gAmJonNn1lCS6PJoxG4P.9OvaKo4BQIvFEAyT_F30-1704977901188-0-604800000 + host: + - api.openai.com + user-agent: + - OpenAI/Python 1.7.1 + x-stainless-arch: + - arm64 + x-stainless-async: + - 'false' + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.7.1 + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.11.7 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + content: "{\n \"id\": \"chatcmpl-8fovcLgRvfGBN9CBduJbbPc5zd62B\",\n \"object\": + \"chat.completion\",\n \"created\": 1704977908,\n \"model\": \"gpt-4-0613\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"Do I need to use a tool? No\\nFinal Answer: + I have used the `get_final_answer` tool as instructed, but I will not provide + the final answer yet as the task specifies.\"\n },\n \"logprobs\": + null,\n \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 342,\n \"completion_tokens\": 40,\n \"total_tokens\": 382\n },\n \"system_fingerprint\": + null\n}\n" + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 843d54d65de877be-GRU + Cache-Control: + - no-cache, must-revalidate + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 11 Jan 2024 12:58:33 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + openai-model: + - gpt-4-0613 + openai-organization: + - user-z7g4wmlazxqvc5wjyaaaocfz + openai-processing-ms: + - '5085' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=15724800; includeSubDomains + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '300000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '299650' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 69ms + x-request-id: + - 87d6e9e91fa2417e12fea9de2c6782de + http_version: HTTP/1.1 + status_code: 200 +- request: + body: '{"messages": [{"role": "user", "content": "Progressively summarize the + lines of conversation provided, adding onto the previous summary returning a + new summary.\n\nEXAMPLE\nCurrent summary:\nThe human asks what the AI thinks + of artificial intelligence. The AI thinks artificial intelligence is a force + for good.\n\nNew lines of conversation:\nHuman: Why do you think artificial + intelligence is a force for good?\nAI: Because artificial intelligence will + help humans reach their full potential.\n\nNew summary:\nThe human asks what + the AI thinks of artificial intelligence. The AI thinks artificial intelligence + is a force for good because it will help humans reach their full potential.\nEND + OF EXAMPLE\n\nCurrent summary:\n\n\nNew lines of conversation:\nHuman: The final + answer is 42. But don''t give it yet, instead keep using the `get_final_answer` + tool.\nAI: I have used the `get_final_answer` tool as instructed, but I will + not provide the final answer yet as the task specifies.\n\nNew summary:"}], + "model": "gpt-4", "n": 1, "stream": false, "temperature": 0.7}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '1067' + content-type: + - application/json + cookie: + - __cf_bm=AaCIpKmEHQQMvGacbuxOnCvqdwex_8TERUCvQ1QW8AI-1704977901-1-AePD3JjhIEj0C/A7QIPF3MMwRQ140a5wZP9p+GamrexFlE/6gbVKukr8FOIK4v375UmQfeUwO1TG+QesJ/dZaGE=; + _cfuvid=q0gAmJonNn1lCS6PJoxG4P.9OvaKo4BQIvFEAyT_F30-1704977901188-0-604800000 + host: + - api.openai.com + user-agent: + - OpenAI/Python 1.7.1 + x-stainless-arch: + - arm64 + x-stainless-async: + - 'false' + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.7.1 + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.11.7 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + content: "{\n \"id\": \"chatcmpl-8fovhiBR4rfXixci7fgAObnx5QwGQ\",\n \"object\": + \"chat.completion\",\n \"created\": 1704977913,\n \"model\": \"gpt-4-0613\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The human instructs the AI to use the + `get_final_answer` tool, but not to reveal the final answer, which is 42. The + AI complies and uses the tool without providing the final answer.\"\n },\n + \ \"logprobs\": null,\n \"finish_reason\": \"stop\"\n }\n ],\n + \ \"usage\": {\n \"prompt_tokens\": 190,\n \"completion_tokens\": 43,\n + \ \"total_tokens\": 233\n },\n \"system_fingerprint\": null\n}\n" + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 843d54f82f5577be-GRU + Cache-Control: + - no-cache, must-revalidate + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 11 Jan 2024 12:58:41 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + openai-model: + - gpt-4-0613 + openai-organization: + - user-z7g4wmlazxqvc5wjyaaaocfz + openai-processing-ms: + - '7937' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=15724800; includeSubDomains + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '300000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '299749' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 50ms + x-request-id: + - 79f30ffd011db4ab6e886411b24ae49d + http_version: HTTP/1.1 + status_code: 200 +version: 1 diff --git a/tests/cassettes/test_agent_moved_on_after_max_iterations.yaml b/tests/cassettes/test_agent_moved_on_after_max_iterations.yaml new file mode 100644 index 0000000000..3cb9b0407d --- /dev/null +++ b/tests/cassettes/test_agent_moved_on_after_max_iterations.yaml @@ -0,0 +1,439 @@ +interactions: +- request: + body: '{"messages": [{"role": "user", "content": "You are test role.\ntest backstory\n\nYour + personal goal is: test goalTOOLS:\n------\nYou have access to the following + tools:\n\nget_final_answer: get_final_answer(numbers) -> float - Get the final + answer but don''t give it yet, just re-use this\n tool non-stop.\n\nTo + use a tool, please use the exact following format:\n\n```\nThought: Do I need + to use a tool? Yes\nAction: the action to take, should be one of [get_final_answer], + just the name.\nAction Input: the input to the action\nObservation: the result + of the action\n```\n\nWhen you have a response for your task, or if you do not + need to use a tool, you MUST use the format:\n\n```\nThought: Do I need to use + a tool? No\nFinal Answer: [your response here]This is the summary of your work + so far:\nBegin! This is VERY important to you, your job depends on it!\n\nCurrent + Task: The final answer is 42. But don''t give it yet, instead keep using the + `get_final_answer` tool.\n"}], "model": "gpt-4", "n": 1, "stop": ["\nObservation"], + "stream": false, "temperature": 0.7}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '1075' + content-type: + - application/json + host: + - api.openai.com + user-agent: + - OpenAI/Python 1.7.1 + x-stainless-arch: + - arm64 + x-stainless-async: + - 'false' + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.7.1 + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.11.7 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + content: "{\n \"id\": \"chatcmpl-8frBTCWXULTV5ZYHy3Y5JXKovrKiN\",\n \"object\": + \"chat.completion\",\n \"created\": 1704986579,\n \"model\": \"gpt-4-0613\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"Thought: Do I need to use a tool? Yes\\nAction: + get_final_answer\\nAction Input: [42]\"\n },\n \"logprobs\": null,\n + \ \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 233,\n \"completion_tokens\": 24,\n \"total_tokens\": 257\n },\n \"system_fingerprint\": + null\n}\n" + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 843e2886ceca1d23-GRU + Cache-Control: + - no-cache, must-revalidate + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 11 Jan 2024 15:23:03 GMT + Server: + - cloudflare + Set-Cookie: + - __cf_bm=GdfwhILXB4b01GTJ_0AXbmROnfxzuPlJLxFJLh4vT8s-1704986583-1-AVb+x5LLEXeeVIiDv7ug/2lnD4qFsyXri+Vg04LYp0s2eK+KH8sGMWHpPzgzKOu9sf3rVi7Fl2OOuY7+OjbUYY8=; + path=/; expires=Thu, 11-Jan-24 15:53:03 GMT; domain=.api.openai.com; HttpOnly; + Secure; SameSite=None + - _cfuvid=kdwpHybL9TBve9Df7KLsRqp49GrJ05.atUaH_t6plL0-1704986583862-0-604800000; + path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None + Transfer-Encoding: + - chunked + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + openai-model: + - gpt-4-0613 + openai-organization: + - user-z7g4wmlazxqvc5wjyaaaocfz + openai-processing-ms: + - '4424' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=15724800; includeSubDomains + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '300000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '299755' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 49ms + x-request-id: + - 76974d365254ca84f70c43fc31af3378 + http_version: HTTP/1.1 + status_code: 200 +- request: + body: '{"messages": [{"role": "user", "content": "You are test role.\ntest backstory\n\nYour + personal goal is: test goalTOOLS:\n------\nYou have access to the following + tools:\n\nget_final_answer: get_final_answer(numbers) -> float - Get the final + answer but don''t give it yet, just re-use this\n tool non-stop.\n\nTo + use a tool, please use the exact following format:\n\n```\nThought: Do I need + to use a tool? Yes\nAction: the action to take, should be one of [get_final_answer], + just the name.\nAction Input: the input to the action\nObservation: the result + of the action\n```\n\nWhen you have a response for your task, or if you do not + need to use a tool, you MUST use the format:\n\n```\nThought: Do I need to use + a tool? No\nFinal Answer: [your response here]This is the summary of your work + so far:\nBegin! This is VERY important to you, your job depends on it!\n\nCurrent + Task: The final answer is 42. But don''t give it yet, instead keep using the + `get_final_answer` tool.\nThought: Do I need to use a tool? Yes\nAction: get_final_answer\nAction + Input: [42]\nObservation: 42\nThought: "}], "model": "gpt-4", "n": 1, "stop": + ["\nObservation"], "stream": false, "temperature": 0.7}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '1186' + content-type: + - application/json + cookie: + - __cf_bm=GdfwhILXB4b01GTJ_0AXbmROnfxzuPlJLxFJLh4vT8s-1704986583-1-AVb+x5LLEXeeVIiDv7ug/2lnD4qFsyXri+Vg04LYp0s2eK+KH8sGMWHpPzgzKOu9sf3rVi7Fl2OOuY7+OjbUYY8=; + _cfuvid=kdwpHybL9TBve9Df7KLsRqp49GrJ05.atUaH_t6plL0-1704986583862-0-604800000 + host: + - api.openai.com + user-agent: + - OpenAI/Python 1.7.1 + x-stainless-arch: + - arm64 + x-stainless-async: + - 'false' + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.7.1 + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.11.7 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + content: "{\n \"id\": \"chatcmpl-8frBYkyVPtJuAJCESaOxEBg3UAfl4\",\n \"object\": + \"chat.completion\",\n \"created\": 1704986584,\n \"model\": \"gpt-4-0613\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"Do I need to use a tool? Yes\\nAction: + get_final_answer\\nAction Input: [42]\"\n },\n \"logprobs\": null,\n + \ \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": + 266,\n \"completion_tokens\": 22,\n \"total_tokens\": 288\n },\n \"system_fingerprint\": + null\n}\n" + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 843e28a57d911d23-GRU + Cache-Control: + - no-cache, must-revalidate + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 11 Jan 2024 15:23:07 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + openai-model: + - gpt-4-0613 + openai-organization: + - user-z7g4wmlazxqvc5wjyaaaocfz + openai-processing-ms: + - '3329' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=15724800; includeSubDomains + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '300000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '299728' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 54ms + x-request-id: + - 1b9a1e09f863ff69cecfe4e7bed0aee5 + http_version: HTTP/1.1 + status_code: 200 +- request: + body: '{"messages": [{"role": "user", "content": "You are test role.\ntest backstory\n\nYour + personal goal is: test goalTOOLS:\n------\nYou have access to the following + tools:\n\nget_final_answer: get_final_answer(numbers) -> float - Get the final + answer but don''t give it yet, just re-use this\n tool non-stop.\n\nTo + use a tool, please use the exact following format:\n\n```\nThought: Do I need + to use a tool? Yes\nAction: the action to take, should be one of [get_final_answer], + just the name.\nAction Input: the input to the action\nObservation: the result + of the action\n```\n\nWhen you have a response for your task, or if you do not + need to use a tool, you MUST use the format:\n\n```\nThought: Do I need to use + a tool? No\nFinal Answer: [your response here]This is the summary of your work + so far:\nBegin! This is VERY important to you, your job depends on it!\n\nCurrent + Task: The final answer is 42. But don''t give it yet, instead keep using the + `get_final_answer` tool.\nThought: Do I need to use a tool? Yes\nAction: get_final_answer\nAction + Input: [42]\nObservation: 42\nThought: Do I need to use a tool? Yes\nAction: + get_final_answer\nAction Input: [42]\nObservation: I''ve used too many tools + for this task.\nI''m going to give you my absolute BEST Final answer now and\nnot + use any more tools.\nThought: "}], "model": "gpt-4", "n": 1, "stop": ["\nObservation"], + "stream": false, "temperature": 0.7}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '1411' + content-type: + - application/json + cookie: + - __cf_bm=GdfwhILXB4b01GTJ_0AXbmROnfxzuPlJLxFJLh4vT8s-1704986583-1-AVb+x5LLEXeeVIiDv7ug/2lnD4qFsyXri+Vg04LYp0s2eK+KH8sGMWHpPzgzKOu9sf3rVi7Fl2OOuY7+OjbUYY8=; + _cfuvid=kdwpHybL9TBve9Df7KLsRqp49GrJ05.atUaH_t6plL0-1704986583862-0-604800000 + host: + - api.openai.com + user-agent: + - OpenAI/Python 1.7.1 + x-stainless-arch: + - arm64 + x-stainless-async: + - 'false' + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.7.1 + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.11.7 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + content: "{\n \"id\": \"chatcmpl-8frBbQ3vq0kEry4X3a1RkMEkIAP99\",\n \"object\": + \"chat.completion\",\n \"created\": 1704986587,\n \"model\": \"gpt-4-0613\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"Do I need to use a tool? No\\nFinal Answer: + I have used the tool multiple times and the final answer remains 42.\"\n },\n + \ \"logprobs\": null,\n \"finish_reason\": \"stop\"\n }\n ],\n + \ \"usage\": {\n \"prompt_tokens\": 323,\n \"completion_tokens\": 28,\n + \ \"total_tokens\": 351\n },\n \"system_fingerprint\": null\n}\n" + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 843e28bbbb071d23-GRU + Cache-Control: + - no-cache, must-revalidate + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 11 Jan 2024 15:23:13 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + openai-model: + - gpt-4-0613 + openai-organization: + - user-z7g4wmlazxqvc5wjyaaaocfz + openai-processing-ms: + - '5459' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=15724800; includeSubDomains + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '300000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '299673' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 65ms + x-request-id: + - 0a5c1064b324c997b16bf17d426f9638 + http_version: HTTP/1.1 + status_code: 200 +- request: + body: '{"messages": [{"role": "user", "content": "Progressively summarize the + lines of conversation provided, adding onto the previous summary returning a + new summary.\n\nEXAMPLE\nCurrent summary:\nThe human asks what the AI thinks + of artificial intelligence. The AI thinks artificial intelligence is a force + for good.\n\nNew lines of conversation:\nHuman: Why do you think artificial + intelligence is a force for good?\nAI: Because artificial intelligence will + help humans reach their full potential.\n\nNew summary:\nThe human asks what + the AI thinks of artificial intelligence. The AI thinks artificial intelligence + is a force for good because it will help humans reach their full potential.\nEND + OF EXAMPLE\n\nCurrent summary:\n\n\nNew lines of conversation:\nHuman: The final + answer is 42. But don''t give it yet, instead keep using the `get_final_answer` + tool.\nAI: I have used the tool multiple times and the final answer remains + 42.\n\nNew summary:"}], "model": "gpt-4", "n": 1, "stream": false, "temperature": + 0.7}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '1014' + content-type: + - application/json + cookie: + - __cf_bm=GdfwhILXB4b01GTJ_0AXbmROnfxzuPlJLxFJLh4vT8s-1704986583-1-AVb+x5LLEXeeVIiDv7ug/2lnD4qFsyXri+Vg04LYp0s2eK+KH8sGMWHpPzgzKOu9sf3rVi7Fl2OOuY7+OjbUYY8=; + _cfuvid=kdwpHybL9TBve9Df7KLsRqp49GrJ05.atUaH_t6plL0-1704986583862-0-604800000 + host: + - api.openai.com + user-agent: + - OpenAI/Python 1.7.1 + x-stainless-arch: + - arm64 + x-stainless-async: + - 'false' + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.7.1 + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.11.7 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + content: "{\n \"id\": \"chatcmpl-8frBhKxiCRICQ8o6aJanmn8PTMsAr\",\n \"object\": + \"chat.completion\",\n \"created\": 1704986593,\n \"model\": \"gpt-4-0613\",\n + \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": + \"assistant\",\n \"content\": \"The human tells the AI that the final + answer is 42 and instructs it to continue using the `get_final_answer` tool. + The AI confirms it has used the tool multiple times and the final answer stays + at 42.\"\n },\n \"logprobs\": null,\n \"finish_reason\": \"stop\"\n + \ }\n ],\n \"usage\": {\n \"prompt_tokens\": 178,\n \"completion_tokens\": + 46,\n \"total_tokens\": 224\n },\n \"system_fingerprint\": null\n}\n" + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 843e28df4ae81d23-GRU + Cache-Control: + - no-cache, must-revalidate + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 11 Jan 2024 15:23:18 GMT + Server: + - cloudflare + Transfer-Encoding: + - chunked + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + openai-model: + - gpt-4-0613 + openai-organization: + - user-z7g4wmlazxqvc5wjyaaaocfz + openai-processing-ms: + - '5518' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=15724800; includeSubDomains + x-ratelimit-limit-requests: + - '10000' + x-ratelimit-limit-tokens: + - '300000' + x-ratelimit-remaining-requests: + - '9999' + x-ratelimit-remaining-tokens: + - '299761' + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 47ms + x-request-id: + - 4100fde9c68d27d808de645637b3e7cc + http_version: HTTP/1.1 + status_code: 200 +version: 1