From 9027246db380faedc4d2d3fcfc7c2e7e138345a3 Mon Sep 17 00:00:00 2001 From: William Fu-Hinthorn <13333726+hinthornw@users.noreply.github.com> Date: Mon, 19 Feb 2024 21:12:27 -0800 Subject: [PATCH] update --- examples/lats/lats.ipynb | 638 ++++++++++++++++++++++++++------------- 1 file changed, 435 insertions(+), 203 deletions(-) diff --git a/examples/lats/lats.ipynb b/examples/lats/lats.ipynb index 0f3719235..121dd77fd 100644 --- a/examples/lats/lats.ipynb +++ b/examples/lats/lats.ipynb @@ -61,7 +61,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 126, "id": "5f43795e-353d-4a35-8dc9-c867b0d18568", "metadata": {}, "outputs": [], @@ -79,7 +79,7 @@ "# Optional: Configure tracing to visualize and debug the agent\n", "_set_if_undefined(\"LANGCHAIN_API_KEY\")\n", "os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n", - "os.environ[\"LANGCHAIN_PROJECT\"] = \"LATS\"\n", + "os.environ[\"LANGCHAIN_PROJECT\"] = \"Reflexion\"\n", "\n", "_set_if_undefined(\"OPENAI_API_KEY\")\n", "_set_if_undefined(\"TAVILY_API_KEY\")" @@ -97,7 +97,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 127, "id": "07f0c534-598b-4ce6-8ec3-eba1e9241a88", "metadata": {}, "outputs": [], @@ -111,7 +111,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 128, "id": "1ff6248c-a7b7-4be1-9c5e-576a05d719ed", "metadata": {}, "outputs": [], @@ -130,7 +130,7 @@ }, { "cell_type": "code", - "execution_count": 160, + "execution_count": 129, "id": "72fc5363-f0f3-4362-8499-14eb583bd75b", "metadata": {}, "outputs": [], @@ -138,75 +138,92 @@ "import datetime\n", "from typing import List\n", "\n", - "from langchain.output_parsers.openai_tools import JsonOutputToolsParser\n", - "from langchain_core.output_parsers import StrOutputParser\n", - "from langchain_core.prompt_values import PromptValue\n", + "from langchain_core.prompt_values import ChatPromptValue\n", "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n", "from langchain_core.pydantic_v1 import BaseModel, Field, ValidationError\n", + "from langchain_core.runnables import RunnableConfig\n", "from langchain_openai import ChatOpenAI\n", + "from langsmith import traceable\n", "\n", "prompt_template = ChatPromptTemplate.from_messages(\n", " [\n", " (\n", " \"system\",\n", - " \"You are a helpful assistant.\",\n", + " \"You are an AI assistant.\",\n", " ),\n", - " (\"user\", \"{input}\"),\n", - " MessagesPlaceholder(variable_name=\"messages\", optional=True),\n", + " MessagesPlaceholder(variable_name=\"messages\"),\n", " ]\n", + ").partial(\n", + " time=lambda: datetime.datetime.now().isoformat(),\n", ")\n", "\n", "\n", - "llm = ChatOpenAI(model=\"gpt-3.5-turbo\")\n", - "initial_answer_chain = prompt_template | llm | StrOutputParser()\n", + "llm = ChatOpenAI(model=\"gpt-4-turbo-preview\")\n", "\n", - "\n", - "def expand(prompt_value: PromptValue, config):\n", - " n = config[\"configurable\"].get(\"n\", 5)\n", - " llm_res = llm.generate([prompt_value.to_messages()], n=n, temperature=1.0)\n", - " # Could consider scoring dupped values higher\n", - " dedupped = {gen.text: gen for gen in llm_res.generations[0]}\n", - " return [AIMessage(content=gen.text) for gen in dedupped.values()]\n", - "\n", - "\n", - "expansion_prompt_template = ChatPromptTemplate.from_messages(\n", - " [\n", - " (\n", - " \"system\",\n", - " \"You are a helpful assistant. Generate an \"\n", - " \"improved response based on the provided reflections.\",\n", - " ),\n", - " (\"user\", \"{input}\"),\n", - " MessagesPlaceholder(variable_name=\"messages\", optional=True),\n", - " ]\n", - ")\n", - "expansion_chain = expansion_prompt_template | expand" + "initial_answer_chain = prompt_template | llm" ] }, { "cell_type": "code", - "execution_count": 148, - "id": "8a215bc6-f3fc-4b4d-98b1-eb760e4c9199", + "execution_count": 130, + "id": "550bff9a-86aa-43ad-ad98-506e97c122d2", "metadata": {}, "outputs": [], "source": [ - "from langchain_core.pydantic_v1 import BaseModel\n", + "# This generates N candidate values\n", + "# for a single input\n", + "def generate_candidates(messages: ChatPromptValue, config: RunnableConfig):\n", + " n = config[\"configurable\"].get(\"N\", 5)\n", + " chat_result = llm.generate([messages.to_messages()], n=n)\n", + " return [AIMessage(content=gen.text) for gen in chat_result.generations[0]]\n", "\n", "\n", - "class Reflection(BaseModel):\n", - " critique: str = Field(\n", - " description=\"~50-100 word critique of the current response, \"\n", - " \"outline parts that are missing, superfluous, or low quality.\"\n", - " )\n", - " is_finished: bool = Field(\n", - " description=\"Whether this response completely and accurately resolves the user's request.\"\n", - " )\n", - " score: int = Field(gte=1, lte=10, description=\"Score of the response.\")" + "expansion_chain = prompt_template | generate_candidates" ] }, { "cell_type": "code", - "execution_count": 164, + "execution_count": 133, + "id": "a6374041-c91b-44eb-b1a2-530d1579b2bc", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.chains import create_structured_output_runnable\n", + "\n", + "\n", + "class Reflection(BaseModel):\n", + " reflections: str = Field(\n", + " description=\"The critique and reflections on the sufficiency, superfluency,\"\n", + " \" and general quality of the response\"\n", + " )\n", + " score: int = Field(\n", + " description=\"Score from 1-10 on the quality of the candidate response.\"\n", + " )\n", + " found_solution: bool = Field(\n", + " description=\"Whether the response has fully solved the question or task.\"\n", + " )\n", + "\n", + "\n", + "prompt = ChatPromptTemplate.from_messages(\n", + " [\n", + " (\n", + " \"system\",\n", + " \"Reflect and grade the assistant response to the user question below.\",\n", + " ),\n", + " MessagesPlaceholder(variable_name=\"input\"),\n", + " MessagesPlaceholder(variable_name=\"candidate\"),\n", + " (\n", + " \"system\",\n", + " \"Reflect on the assistant response above, critique, and score the response.\",\n", + " ),\n", + " ]\n", + ")\n", + "reflection_chain = create_structured_output_runnable(output_schema=Reflection, llm=llm)" + ] + }, + { + "cell_type": "code", + "execution_count": 118, "id": "c1219cd1-6cfb-4c83-8579-d3a003569150", "metadata": {}, "outputs": [], @@ -217,7 +234,7 @@ "class Node:\n", " def __init__(\n", " self,\n", - " solution: str,\n", + " solution: AIMessage,\n", " parent: Optional[Node] = None,\n", " reflection: Optional[Reflection] = None,\n", " ):\n", @@ -227,54 +244,79 @@ " self.value = 0\n", " self.visits = 0\n", " self.reflection = reflection\n", - " self.is_finished = False\n", - " if reflection is None and reflection.is_finished:\n", - " self._mark_as_finished()\n", + " self._is_solved = reflection.found_solution\n", + " if self._is_solved:\n", + " self._mark_tree_as_solved()\n", "\n", - " def upper_confidence_bound(self, exploration_weight: float = 1.0):\n", - " if self.parent is None:\n", - " raise ValueError(\"Cannot compute UTC for root node.\")\n", + " @property\n", + " def is_solved(self):\n", + " return self._is_solved\n", + "\n", + " def _mark_tree_as_solved(self):\n", + " parent = self.parent\n", + " while parent:\n", + " parent._is_solved = True\n", + " parent = parent.parent\n", + "\n", + " def add_reflection(self, reflection: Reflection):\n", + " if self.reflection is not None:\n", + " raise ValueError(\"Cannot overwrite exisitng reflection\")\n", + " self.reflection = reflection\n", + " if reflection.is_solved:\n", + " self._is_solved = reflection.is_solved\n", + " self._mark_tree_as_solved()\n", + "\n", + " def uct(self, exploration_weight=1.0):\n", " if self.visits == 0:\n", " return self.value\n", " return (self.value / self.visits) + exploration_weight * math.sqrt(\n", " math.log(self.parent.visits) / self.visits\n", " )\n", "\n", - " @property\n", " def best_child(self):\n", " if not self.children:\n", " return None\n", " return max(self.children, key=lambda child: child.uct())\n", "\n", - " @property\n", - " def best_child_score(self):\n", + " def best_child_value(self):\n", " if not self.children:\n", " return None\n", " return max(self.children, key=lambda child: child.value)\n", "\n", - " @property\n", - " def depth_at_node(self):\n", - " if self.children:\n", - " return 1 + max([child.depth_at_node for child in self.children])\n", - " return 1\n", - "\n", - " def add_reflection(self, reflection: Reflection):\n", - " if self.reflection is not None:\n", - " raise ValueError(\"Cannot overwrite existing reflection\")\n", - " self.reflection = reflection\n", - " if reflection is None and reflection.is_finished:\n", - " self._mark_as_finished()\n", - "\n", " def update(self, reward: float):\n", " self.visits += 1\n", " self.value += reward\n", "\n", - " def _mark_as_finished(self):\n", - " self.is_finished = True\n", + " def get_messages(self) -> List[BaseMessage]:\n", + " messages = []\n", " parent = self.parent\n", " while parent:\n", - " parent.is_finished = True\n", - " parent = parent.parent" + " messages.extend(\n", + " [\n", + " HumanMessage(content=self.reflection),\n", + " self.solution,\n", + " ]\n", + " )\n", + " return messages[::-1] # root solution, reflection, child 1, ...\n", + "\n", + " @property\n", + " def max_depth(self) -> int:\n", + " if self.children:\n", + " return 1 + max([child.max_depth for child in self.children])\n", + " return 1" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "id": "152d2d40-11e2-4922-82d7-592bdd90b7d3", + "metadata": {}, + "outputs": [], + "source": [ + "# def get_score():\n", + "# (self.value / self.visits) + exploration_weight * math.sqrt(\n", + "# math.log(self.parent.visits) / self.visits\n", + "# )" ] }, { @@ -291,16 +333,6 @@ "c.. # context" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "63ef2b7d-d73e-4073-b549-f37b96011145", - "metadata": {}, - "outputs": [], - "source": [ - "from " - ] - }, { "cell_type": "markdown", "id": "d9c1ba9b-a083-443c-af82-fa116fc450de", @@ -322,149 +354,349 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 138, + "id": "47b43e08-ee04-4121-a294-fbbd5a4e3995", + "metadata": {}, + "outputs": [], + "source": [ + "import operator\n", + "from collections import deque\n", + "\n", + "from typing_extensions import Annotated, TypedDict\n", + "\n", + "from langgraph.graph import StateGraph\n", + "\n", + "\n", + "class TreeState(TypedDict):\n", + " # The full tree\n", + " root: Node\n", + " # The rolled-out steps so far\n", + " input: str\n", + " solution: AIMessage\n", + "\n", + "\n", + "builder = StateGraph(TreeState)\n", + "\n", + "\n", + "def start(state: TreeState) -> dict:\n", + " user_input = [HumanMessage(content=state[\"input\"])]\n", + " res = initial_answer_chain.invoke({\"messages\": user_input})\n", + " reflection = reflection_chain.invoke({\"input\": user_input, \"candidate\": [res]})\n", + " root = Node(res, reflection)\n", + " return {\n", + " **state,\n", + " \"root\": root,\n", + " }\n", + "\n", + "\n", + "def expand(state: TreeState, config: RunnableConfig) -> dict:\n", + " root = state[\"root\"]\n", + " user_input = [HumanMessage(content=state[\"input\"])]\n", + " best_candidate: Node = root.best_child()\n", + " messages = user_input + best_candidate.get_messages()\n", + " # Generate N candidates from the single child candidate\n", + " new_candidates = expansion_chain.invoke({\"messages\": messages}, config)\n", + " # Reflect on each candidate\n", + " # For tasks with external validation, you'd add that here.\n", + " reflections = reflection_chain.batch(\n", + " [[{\"input\": user_input, \"candidate\": [msg]}] for msg in new_candidates],\n", + " config,\n", + " )\n", + " # Grow tree\n", + " child_nodes = [\n", + " Node(cand, reflection) for cand, reflection in zip(new_candidates, reflections)\n", + " ]\n", + " best_candidate.children.extend(child_nodes)\n", + " # We have already extended the tree directly, so we just return the state\n", + " return state\n", + "\n", + "\n", + "def select_solution(state: TreeState):\n", + " all_nodes = []\n", + " nodes = deque()\n", + " nodes.append(state[\"root\"])\n", + " while nodes:\n", + " node = nodes.popleft()\n", + " all_nodes.extend(node.children)\n", + " for n in node.children:\n", + " nodes.append(n)\n", + " # TODO: Diff between value and reward?\n", + " best_node = max(all_nodes, key=lambda node: node.value)\n", + " return {**state, \"solution\": best_node.solution}\n", + "\n", + "\n", + "def should_loop(state: TreeState):\n", + " root = state[\"root\"]\n", + " if root.is_solved:\n", + " return \"select_solution\"\n", + " if root.max_depth() > 5:\n", + " return \"select_solution\"\n", + " return \"expand\"\n", + "\n", + "\n", + "builder.add_node(\"start\", start)\n", + "builder.add_node(\"expand\", expand)\n", + "builder.add_node(\"select_solution\", select_solution)\n", + "builder.set_entry_point(\"start\")\n", + "\n", + "\n", + "builder.add_conditional_edges(\n", + " \"start\",\n", + " # Either expand/rollout or finish\n", + " should_loop,\n", + ")\n", + "builder.add_conditional_edges(\n", + " \"expand\",\n", + " # Either continue to rollout or finish\n", + " should_loop,\n", + ")\n", + "\n", + "builder.set_finish_point(\"select_solution\")\n", + "graph = builder.compile()" + ] + }, + { + "cell_type": "code", + "execution_count": 140, + "id": "58d7a4af-a78b-409d-a042-73596546679f", + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "Invalid input type . Must be a PromptValue, str, or list of BaseMessages.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[140], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mgraph\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43minput\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mwhat\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43ms the capital of ninevah\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langgraph/pregel/__init__.py:579\u001b[0m, in \u001b[0;36mPregel.invoke\u001b[0;34m(self, input, config, output_keys, input_keys, **kwargs)\u001b[0m\n\u001b[1;32m 569\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[1;32m 570\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 571\u001b[0m \u001b[38;5;28minput\u001b[39m: Union[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any], Any],\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 576\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m 577\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Union[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any], Any]:\n\u001b[1;32m 578\u001b[0m latest: Union[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any], Any] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m--> 579\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mchunk\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstream\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 580\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 581\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 582\u001b[0m \u001b[43m \u001b[49m\u001b[43moutput_keys\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moutput_keys\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43moutput_keys\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mis\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mnot\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moutput\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 583\u001b[0m \u001b[43m \u001b[49m\u001b[43minput_keys\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minput_keys\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 584\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 585\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m:\u001b[49m\n\u001b[1;32m 586\u001b[0m \u001b[43m \u001b[49m\u001b[43mlatest\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mchunk\u001b[49m\n\u001b[1;32m 587\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m latest\n", + "File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langgraph/pregel/__init__.py:615\u001b[0m, in \u001b[0;36mPregel.transform\u001b[0;34m(self, input, config, output_keys, input_keys, **kwargs)\u001b[0m\n\u001b[1;32m 606\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mtransform\u001b[39m(\n\u001b[1;32m 607\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 608\u001b[0m \u001b[38;5;28minput\u001b[39m: Iterator[Union[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any], Any]],\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 613\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m 614\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Iterator[Union[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any], Any]]:\n\u001b[0;32m--> 615\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mchunk\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_transform_stream_with_config\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 616\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 617\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_transform\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 618\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 619\u001b[0m \u001b[43m \u001b[49m\u001b[43moutput_keys\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moutput_keys\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 620\u001b[0m \u001b[43m \u001b[49m\u001b[43minput_keys\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minput_keys\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 621\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 622\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m:\u001b[49m\n\u001b[1;32m 623\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01myield\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mchunk\u001b[49m\n", + "File \u001b[0;32m~/code/lc/langchain/libs/core/langchain_core/runnables/base.py:1497\u001b[0m, in \u001b[0;36mRunnable._transform_stream_with_config\u001b[0;34m(self, input, transformer, config, run_type, **kwargs)\u001b[0m\n\u001b[1;32m 1495\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1496\u001b[0m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m:\n\u001b[0;32m-> 1497\u001b[0m chunk: Output \u001b[38;5;241m=\u001b[39m context\u001b[38;5;241m.\u001b[39mrun(\u001b[38;5;28mnext\u001b[39m, iterator) \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n\u001b[1;32m 1498\u001b[0m \u001b[38;5;28;01myield\u001b[39;00m chunk\n\u001b[1;32m 1499\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m final_output_supported:\n", + "File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langgraph/pregel/__init__.py:355\u001b[0m, in \u001b[0;36mPregel._transform\u001b[0;34m(self, input, run_manager, config, input_keys, output_keys, interrupt)\u001b[0m\n\u001b[1;32m 348\u001b[0m done, inflight \u001b[38;5;241m=\u001b[39m concurrent\u001b[38;5;241m.\u001b[39mfutures\u001b[38;5;241m.\u001b[39mwait(\n\u001b[1;32m 349\u001b[0m futures,\n\u001b[1;32m 350\u001b[0m return_when\u001b[38;5;241m=\u001b[39mconcurrent\u001b[38;5;241m.\u001b[39mfutures\u001b[38;5;241m.\u001b[39mFIRST_EXCEPTION,\n\u001b[1;32m 351\u001b[0m timeout\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstep_timeout,\n\u001b[1;32m 352\u001b[0m )\n\u001b[1;32m 354\u001b[0m \u001b[38;5;66;03m# interrupt on failure or timeout\u001b[39;00m\n\u001b[0;32m--> 355\u001b[0m \u001b[43m_interrupt_or_proceed\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdone\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minflight\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstep\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 357\u001b[0m \u001b[38;5;66;03m# apply writes to channels\u001b[39;00m\n\u001b[1;32m 358\u001b[0m _apply_writes(\n\u001b[1;32m 359\u001b[0m checkpoint, channels, pending_writes, config, step \u001b[38;5;241m+\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[1;32m 360\u001b[0m )\n", + "File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/site-packages/langgraph/pregel/__init__.py:698\u001b[0m, in \u001b[0;36m_interrupt_or_proceed\u001b[0;34m(done, inflight, step)\u001b[0m\n\u001b[1;32m 696\u001b[0m inflight\u001b[38;5;241m.\u001b[39mpop()\u001b[38;5;241m.\u001b[39mcancel()\n\u001b[1;32m 697\u001b[0m \u001b[38;5;66;03m# raise the exception\u001b[39;00m\n\u001b[0;32m--> 698\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m exc\n\u001b[1;32m 699\u001b[0m \u001b[38;5;66;03m# TODO this is where retry of an entire step would happen\u001b[39;00m\n\u001b[1;32m 701\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m inflight:\n\u001b[1;32m 702\u001b[0m \u001b[38;5;66;03m# if we got here means we timed out\u001b[39;00m\n", + "File \u001b[0;32m~/.pyenv/versions/3.11.2/lib/python3.11/concurrent/futures/thread.py:58\u001b[0m, in \u001b[0;36m_WorkItem.run\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 55\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m\n\u001b[1;32m 57\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 58\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 59\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m exc:\n\u001b[1;32m 60\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfuture\u001b[38;5;241m.\u001b[39mset_exception(exc)\n", + "File \u001b[0;32m~/code/lc/langchain/libs/core/langchain_core/runnables/base.py:4064\u001b[0m, in \u001b[0;36mRunnableBindingBase.invoke\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m 4058\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[1;32m 4059\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 4060\u001b[0m \u001b[38;5;28minput\u001b[39m: Input,\n\u001b[1;32m 4061\u001b[0m config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 4062\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Optional[Any],\n\u001b[1;32m 4063\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Output:\n\u001b[0;32m-> 4064\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbound\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 4065\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 4066\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_merge_configs\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 4067\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m{\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m}\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 4068\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/code/lc/langchain/libs/core/langchain_core/runnables/base.py:2053\u001b[0m, in \u001b[0;36mRunnableSequence.invoke\u001b[0;34m(self, input, config)\u001b[0m\n\u001b[1;32m 2051\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 2052\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i, step \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msteps):\n\u001b[0;32m-> 2053\u001b[0m \u001b[38;5;28minput\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[43mstep\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 2054\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 2055\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# mark each step as a child run\u001b[39;49;00m\n\u001b[1;32m 2056\u001b[0m \u001b[43m \u001b[49m\u001b[43mpatch_config\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 2057\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallbacks\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrun_manager\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_child\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43mf\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mseq:step:\u001b[39;49m\u001b[38;5;132;43;01m{\u001b[39;49;00m\u001b[43mi\u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[38;5;132;43;01m}\u001b[39;49;00m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2058\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 2059\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2060\u001b[0m \u001b[38;5;66;03m# finish the root run\u001b[39;00m\n\u001b[1;32m 2061\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n", + "File \u001b[0;32m~/code/lc/langchain/libs/core/langchain_core/runnables/base.py:3507\u001b[0m, in \u001b[0;36mRunnableLambda.invoke\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m 3505\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Invoke this runnable synchronously.\"\"\"\u001b[39;00m\n\u001b[1;32m 3506\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mhasattr\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfunc\u001b[39m\u001b[38;5;124m\"\u001b[39m):\n\u001b[0;32m-> 3507\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_call_with_config\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 3508\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_invoke\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 3509\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 3510\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_config\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfunc\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 3511\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 3512\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3513\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 3514\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\n\u001b[1;32m 3515\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCannot invoke a coroutine function synchronously.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 3516\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUse `ainvoke` instead.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 3517\u001b[0m )\n", + "File \u001b[0;32m~/code/lc/langchain/libs/core/langchain_core/runnables/base.py:1246\u001b[0m, in \u001b[0;36mRunnable._call_with_config\u001b[0;34m(self, func, input, config, run_type, **kwargs)\u001b[0m\n\u001b[1;32m 1242\u001b[0m context \u001b[38;5;241m=\u001b[39m copy_context()\n\u001b[1;32m 1243\u001b[0m context\u001b[38;5;241m.\u001b[39mrun(var_child_runnable_config\u001b[38;5;241m.\u001b[39mset, child_config)\n\u001b[1;32m 1244\u001b[0m output \u001b[38;5;241m=\u001b[39m cast(\n\u001b[1;32m 1245\u001b[0m Output,\n\u001b[0;32m-> 1246\u001b[0m \u001b[43mcontext\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1247\u001b[0m \u001b[43m \u001b[49m\u001b[43mcall_func_with_variable_args\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1248\u001b[0m \u001b[43m \u001b[49m\u001b[43mfunc\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type]\u001b[39;49;00m\n\u001b[1;32m 1249\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type]\u001b[39;49;00m\n\u001b[1;32m 1250\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1251\u001b[0m \u001b[43m \u001b[49m\u001b[43mrun_manager\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1252\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1253\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m 1254\u001b[0m )\n\u001b[1;32m 1255\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 1256\u001b[0m run_manager\u001b[38;5;241m.\u001b[39mon_chain_error(e)\n", + "File \u001b[0;32m~/code/lc/langchain/libs/core/langchain_core/runnables/config.py:326\u001b[0m, in \u001b[0;36mcall_func_with_variable_args\u001b[0;34m(func, input, config, run_manager, **kwargs)\u001b[0m\n\u001b[1;32m 324\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m run_manager \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m accepts_run_manager(func):\n\u001b[1;32m 325\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrun_manager\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m run_manager\n\u001b[0;32m--> 326\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/code/lc/langchain/libs/core/langchain_core/runnables/base.py:3383\u001b[0m, in \u001b[0;36mRunnableLambda._invoke\u001b[0;34m(self, input, run_manager, config, **kwargs)\u001b[0m\n\u001b[1;32m 3381\u001b[0m output \u001b[38;5;241m=\u001b[39m chunk\n\u001b[1;32m 3382\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 3383\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[43mcall_func_with_variable_args\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 3384\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfunc\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mrun_manager\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\n\u001b[1;32m 3385\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3386\u001b[0m \u001b[38;5;66;03m# If the output is a runnable, invoke it\u001b[39;00m\n\u001b[1;32m 3387\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(output, Runnable):\n", + "File \u001b[0;32m~/code/lc/langchain/libs/core/langchain_core/runnables/config.py:326\u001b[0m, in \u001b[0;36mcall_func_with_variable_args\u001b[0;34m(func, input, config, run_manager, **kwargs)\u001b[0m\n\u001b[1;32m 324\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m run_manager \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m accepts_run_manager(func):\n\u001b[1;32m 325\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrun_manager\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m run_manager\n\u001b[0;32m--> 326\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn[138], line 23\u001b[0m, in \u001b[0;36mstart\u001b[0;34m(state)\u001b[0m\n\u001b[1;32m 21\u001b[0m user_input \u001b[38;5;241m=\u001b[39m [HumanMessage(content\u001b[38;5;241m=\u001b[39mstate[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124minput\u001b[39m\u001b[38;5;124m\"\u001b[39m])]\n\u001b[1;32m 22\u001b[0m res \u001b[38;5;241m=\u001b[39m initial_answer_chain\u001b[38;5;241m.\u001b[39minvoke({\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmessages\u001b[39m\u001b[38;5;124m\"\u001b[39m: user_input})\n\u001b[0;32m---> 23\u001b[0m reflection \u001b[38;5;241m=\u001b[39m \u001b[43mreflection_chain\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43minput\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43muser_input\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mcandidate\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[43mres\u001b[49m\u001b[43m]\u001b[49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 24\u001b[0m root \u001b[38;5;241m=\u001b[39m Node(res, reflection)\n\u001b[1;32m 25\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m {\n\u001b[1;32m 26\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mstate,\n\u001b[1;32m 27\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mroot\u001b[39m\u001b[38;5;124m\"\u001b[39m: root,\n\u001b[1;32m 28\u001b[0m }\n", + "File \u001b[0;32m~/code/lc/langchain/libs/core/langchain_core/runnables/base.py:2053\u001b[0m, in \u001b[0;36mRunnableSequence.invoke\u001b[0;34m(self, input, config)\u001b[0m\n\u001b[1;32m 2051\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 2052\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i, step \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msteps):\n\u001b[0;32m-> 2053\u001b[0m \u001b[38;5;28minput\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[43mstep\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 2054\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 2055\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# mark each step as a child run\u001b[39;49;00m\n\u001b[1;32m 2056\u001b[0m \u001b[43m \u001b[49m\u001b[43mpatch_config\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 2057\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallbacks\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrun_manager\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_child\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43mf\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mseq:step:\u001b[39;49m\u001b[38;5;132;43;01m{\u001b[39;49;00m\u001b[43mi\u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[38;5;132;43;01m}\u001b[39;49;00m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2058\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 2059\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2060\u001b[0m \u001b[38;5;66;03m# finish the root run\u001b[39;00m\n\u001b[1;32m 2061\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n", + "File \u001b[0;32m~/code/lc/langchain/libs/core/langchain_core/runnables/base.py:4064\u001b[0m, in \u001b[0;36mRunnableBindingBase.invoke\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m 4058\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[1;32m 4059\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 4060\u001b[0m \u001b[38;5;28minput\u001b[39m: Input,\n\u001b[1;32m 4061\u001b[0m config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 4062\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Optional[Any],\n\u001b[1;32m 4063\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Output:\n\u001b[0;32m-> 4064\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbound\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 4065\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 4066\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_merge_configs\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 4067\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m{\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m}\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 4068\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/code/lc/langchain/libs/core/langchain_core/language_models/chat_models.py:167\u001b[0m, in \u001b[0;36mBaseChatModel.invoke\u001b[0;34m(self, input, config, stop, **kwargs)\u001b[0m\n\u001b[1;32m 155\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[1;32m 156\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 157\u001b[0m \u001b[38;5;28minput\u001b[39m: LanguageModelInput,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 161\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m 162\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m BaseMessage:\n\u001b[1;32m 163\u001b[0m config \u001b[38;5;241m=\u001b[39m ensure_config(config)\n\u001b[1;32m 164\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m cast(\n\u001b[1;32m 165\u001b[0m ChatGeneration,\n\u001b[1;32m 166\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mgenerate_prompt(\n\u001b[0;32m--> 167\u001b[0m [\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_convert_input\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m)\u001b[49m],\n\u001b[1;32m 168\u001b[0m stop\u001b[38;5;241m=\u001b[39mstop,\n\u001b[1;32m 169\u001b[0m callbacks\u001b[38;5;241m=\u001b[39mconfig\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcallbacks\u001b[39m\u001b[38;5;124m\"\u001b[39m),\n\u001b[1;32m 170\u001b[0m tags\u001b[38;5;241m=\u001b[39mconfig\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtags\u001b[39m\u001b[38;5;124m\"\u001b[39m),\n\u001b[1;32m 171\u001b[0m metadata\u001b[38;5;241m=\u001b[39mconfig\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmetadata\u001b[39m\u001b[38;5;124m\"\u001b[39m),\n\u001b[1;32m 172\u001b[0m run_name\u001b[38;5;241m=\u001b[39mconfig\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrun_name\u001b[39m\u001b[38;5;124m\"\u001b[39m),\n\u001b[1;32m 173\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs,\n\u001b[1;32m 174\u001b[0m )\u001b[38;5;241m.\u001b[39mgenerations[\u001b[38;5;241m0\u001b[39m][\u001b[38;5;241m0\u001b[39m],\n\u001b[1;32m 175\u001b[0m )\u001b[38;5;241m.\u001b[39mmessage\n", + "File \u001b[0;32m~/code/lc/langchain/libs/core/langchain_core/language_models/chat_models.py:150\u001b[0m, in \u001b[0;36mBaseChatModel._convert_input\u001b[0;34m(self, input)\u001b[0m\n\u001b[1;32m 148\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m ChatPromptValue(messages\u001b[38;5;241m=\u001b[39mconvert_to_messages(\u001b[38;5;28minput\u001b[39m))\n\u001b[1;32m 149\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 150\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 151\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInvalid input type \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(\u001b[38;5;28minput\u001b[39m)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m. \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 152\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMust be a PromptValue, str, or list of BaseMessages.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 153\u001b[0m )\n", + "\u001b[0;31mValueError\u001b[0m: Invalid input type . Must be a PromptValue, str, or list of BaseMessages." + ] + } + ], + "source": [ + "graph.invoke({\"input\": \"what's the capital of ninevah\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 123, "id": "bc7ba5b1-0f4e-40cb-a4d1-f86dc935742f", "metadata": {}, "outputs": [], "source": [ "# with langsmith.trace(\"mcts\", inputs={\"item\": item}) as trace:\n", - "# # Get the first output\n", - "# cur_func_impl = gen.func_impl(item[\"prompt\"], model, \"simple\")\n", - "# root = Node(cur_func_impl) # initial solution (for pass@1 metric)\n", - "# test_feedback.append(feedback)\n", - "# with langsmith.trace(\n", - "# \"self_reflection\", inputs={\"fun\": cur_func_impl}\n", - "# ) as trace:\n", - "# reflection = gen.self_reflection(cur_func_impl, feedback, model)\n", - "# trace.end(outputs={\"reflection\": reflection})\n", - "# reflections += [reflection]\n", - "# root.test_feedback = feedback\n", - "# root.reflection = reflection\n", + "# if is_leetcode:\n", + "# tests_i = item[\"visible_tests\"]\n", + "# else:\n", + "# tests_i = gen.internal_tests(item[\"prompt\"], test_model, 6)\n", "\n", - "# for cur_iter in range(max_iters):\n", - "# # Selection\n", + "# with langsmith.trace(\n", + "# \"first_attempt\", inputs={\"item\": item}\n", + "# ) as trace:\n", + "# while cur_func_impl is None:\n", + "# cur_func_impl = gen.func_impl(item[\"prompt\"], model, \"simple\")\n", + "# trace.end(outputs={\"cur_func_impl\": cur_func_impl})\n", + "# root = Node(cur_func_impl) # initial solution (for pass@1 metric)\n", "\n", - "# node = root\n", - "# trajectory = {\"solutions\": [], \"feedbacks\": []}\n", + "# # Lists for logging\n", + "# reflections = []\n", + "# implementations = []\n", + "# test_feedback = []\n", + "# is_solved = False\n", "\n", - "# while node.children:\n", - "# node = node.best_child()\n", - "# trajectory[\"solutions\"].append(node.solution)\n", + "# # first attempt\n", "\n", - "# # Expansion\n", - "# for _ in range(n):\n", - "# new_solution = None\n", - "# strategy = \"mcts\"\n", - "# prev_func_impl = node.solution\n", - "# feedback = node.test_feedback\n", - "# reflection = node.reflection\n", - "# acc_feedback, acc_reflection = gather_context_from_tree(node)\n", - "# new_solution = gen.func_impl(\n", - "# func_sig=item[\"prompt\"],\n", - "# model=model,\n", - "# strategy=strategy,\n", - "# prev_func_impl=prev_func_impl,\n", - "# feedback=feedback,\n", - "# self_reflection=reflection,\n", - "# acc_feedback=acc_feedback,\n", - "# acc_reflection=acc_reflection,\n", + "# implementations.append(cur_func_impl)\n", + "# assert isinstance(cur_func_impl, str)\n", + "# is_passing, feedback, _ = exe.execute(cur_func_impl, tests_i)\n", + "# trace.end(outputs={\"is_passing\": is_passing, \"feedback\": feedback})\n", + "# test_feedback.append(feedback)\n", + "# with langsmith.trace(\n", + "# \"self_reflection\", inputs={\"fun\": cur_func_impl}\n", + "# ) as trace:\n", + "# reflection = gen.self_reflection(cur_func_impl, feedback, model)\n", + "# trace.end(outputs={\"reflection\": reflection})\n", + "# reflections += [reflection]\n", + "# root.test_feedback = feedback\n", + "# root.reflection = reflection\n", + "\n", + "# for cur_iter in range(max_iters):\n", + "# # Selection\n", + "\n", + "# node = root\n", + "# trajectory = {\"solutions\": [], \"feedbacks\": []}\n", + "\n", + "# while node.children:\n", + "# node = node.best_child()\n", + "# trajectory[\"solutions\"].append(node.solution)\n", + "\n", + "# # Expansion\n", + "# for _ in range(n):\n", + "# new_solution = None\n", + "# strategy = \"mcts\"\n", + "# prev_func_impl = node.solution\n", + "# feedback = node.test_feedback\n", + "# reflection = node.reflection\n", + "# acc_feedback, acc_reflection = gather_context_from_tree(node)\n", + "# with langsmith.trace(\n", + "# f\"expansion-{_}\", inputs={\"func_sig\": item[\"prompt\"], \"model\": model}\n", + "# ) as trace:\n", + "# while new_solution is None:\n", + "\n", + "# new_solution = gen.func_impl(\n", + "# # func_sig=item[\"prompt\"],\n", + "# # model=model,\n", + "# # strategy=strategy,\n", + "# prev_func_impl=prev_func_impl,\n", + "# feedback=feedback,\n", + "# self_reflection=reflection,\n", + "# # is this the stuff that's unique?\n", + "# acc_feedback=acc_feedback,\n", + "# acc_reflection=acc_reflection,\n", + "# )\n", + "\n", + "# combined_context = \"\\nPrevious Trial\\n\\n\" + new_solution\n", + "\n", + "# child = Node(\n", + "# new_solution,\n", + "# parent=node,\n", + "# context=combined_context,\n", + "# depth=node.depth + 1,\n", "# )\n", + "# node.children.append(child)\n", "\n", - "# combined_context = \"\\nPrevious Trial\\n\\n\" + new_solution\n", - "\n", - "# child = Node(\n", - "# new_solution,\n", - "# parent=node,\n", - "# context=combined_context,\n", - "# depth=node.depth + 1,\n", - "# )\n", - "# node.children.append(child)\n", - "\n", - "# # Simulation\n", - "# reward_real = 0\n", - "# for child in node.children:\n", - "# reflection = gen.self_reflection(\n", - "# child.solution, feedback_internal, model\n", - "# )\n", - "# reflections.append(reflection)\n", - "# child.reflection = reflection\n", - "# child.test_feedback = feedback_internal\n", - "# child.context += (\n", - "# \"\\n\\nPrevious Trial\\n\\n\"\n", - "# + child.solution\n", - "# + \"\\n\\nTest results: \\n\"\n", - "# + feedback_internal\n", - "# + \"\\n\\nSelf-reflection: \"\n", - "# + reflection\n", - "# )\n", - "\n", - "# if \"Tested passed:\" in feedback_internal:\n", - "# # Split at \"Tests failed:\" and get the part before it (which contains the passed tests)\n", - "# passed_section = feedback_internal.split(\"Tests failed:\")[0]\n", - "# # Split at \"Tested passed:\" and get the part after it, then count the non-empty lines\n", - "# reward_internal = len(\n", - "# [\n", - "# line\n", - "# for line in passed_section.split(\"Tested passed:\")[\n", - "# 1\n", - "# ].splitlines()\n", - "# if line.strip() != \"\"\n", - "# ]\n", + "# # Simulation\n", + "# reward_real = 0\n", + "# for child in node.children:\n", + "# is_passing_internal, feedback_internal, _ = exe.execute(\n", + "# child.solution, tests_i\n", "# )\n", - "# reward_internal = reward_internal / len(tests_i)\n", - "# else:\n", - "# reward_internal = 0\n", - "# if is_passing_internal or cur_iter == max_iters - 1:\n", - "# is_passing = exe.evaluate(\n", - "# item[\"entry_point\"],\n", - "# child.solution,\n", - "# item[\"test\"],\n", - "# timeout=10,\n", - "# )\n", - "# if is_passing:\n", - "# item[\"solution\"] = child.solution\n", - "# is_solved = True\n", - "# reward_real = 1\n", + "# if not is_passing_internal:\n", + "# reflection = gen.self_reflection(\n", + "# child.solution, feedback_internal, model\n", + "# )\n", + "# reflections.append(reflection)\n", + "# child.reflection = reflection\n", + "# child.test_feedback = feedback_internal\n", + "# child.context += (\n", + "# \"\\n\\nPrevious Trial\\n\\n\"\n", + "# + child.solution\n", + "# + \"\\n\\nTest results: \\n\"\n", + "# + feedback_internal\n", + "# + \"\\n\\nSelf-reflection: \"\n", + "# + reflection\n", + "# )\n", + "# else:\n", + "# child.context += (\n", + "# \"\\n\\nPrevious Trial\\n\\n\"\n", + "# + child.solution\n", + "# + \"\\n\\nTest results: \\n\"\n", + "# + feedback_internal\n", + "# )\n", + "# child.reflection = \"\"\n", + "# child.test_feedback = feedback_internal\n", + "\n", + "# if \"Tested passed:\" in feedback_internal:\n", + "# # Split at \"Tests failed:\" and get the part before it (which contains the passed tests)\n", + "# passed_section = feedback_internal.split(\"Tests failed:\")[0]\n", + "# # Split at \"Tested passed:\" and get the part after it, then count the non-empty lines\n", + "# reward_internal = len(\n", + "# [\n", + "# line\n", + "# for line in passed_section.split(\"Tested passed:\")[\n", + "# 1\n", + "# ].splitlines()\n", + "# if line.strip() != \"\"\n", + "# ]\n", + "# )\n", + "# reward_internal = reward_internal / len(tests_i)\n", + "# else:\n", + "# reward_internal = 0\n", + "# if is_passing_internal or cur_iter == max_iters - 1:\n", + "# is_passing = exe.evaluate(\n", + "# item[\"entry_point\"],\n", + "# child.solution,\n", + "# item[\"test\"],\n", + "# timeout=10,\n", + "# )\n", + "# if is_passing:\n", + "# item[\"solution\"] = child.solution\n", + "# is_solved = True\n", + "# reward_real = 1\n", + "# break\n", + "\n", + "# if is_solved:\n", "# break\n", "\n", - "# if is_solved:\n", - "# break\n", - "# reward = reward_internal + reward_real\n", - "# child.update(reward)\n", + "# print(reward_internal)\n", + "# print(reward_real)\n", + "# reward = reward_internal + reward_real\n", + "# child.update(reward)\n", "\n", - "# # Backpropagation\n", - "# temp = child\n", - "# while temp.parent:\n", - "# temp = temp.parent\n", - "# temp.update(reward)\n", + "# # Backpropagation\n", + "# temp = child\n", + "# while temp.parent:\n", + "# temp = temp.parent\n", + "# temp.update(reward)\n", "\n", - "# # Choose the best solution after all iterations\n", - "# best_solution = root.best_child_value().solution\n", - "# item[\"solution\"] = best_solution\n", - "# reflections.append(\"MCTS reflections\")\n", - "# implementations.append(best_solution)" - ] - }, - { - "cell_type": "code", - "execution_count": 144, - "id": "8ebb3a4f-d81e-4238-9c60-8004cedef454", - "metadata": {}, - "outputs": [], - "source": [ - "# from datasets import load_dataset\n", + "# # Choose the best solution after all iterations\n", + "# if is_solved:\n", + "# best_solution = item[\"solution\"]\n", + "# else:\n", + "# best_solution = root.best_child_value().solution\n", + "# item[\"solution\"] = best_solution\n", "\n", - "# dataset = load_dataset(\"deepmind/code_contests\", split=\"valid\")\n", - "# example = dataset[70]" + "# is_passing, cur_feedback, _ = exe.execute(new_solution, tests_i)\n", + "# test_feedback.append(cur_feedback)\n", + "# is_passing = exe.evaluate(\n", + "# item[\"entry_point\"], best_solution, item[\"test\"], timeout=10\n", + "# )\n", + "# if is_passing:\n", + "# num_success += 1\n", + "\n", + "# reflections.append(\"MCTS reflections\")\n", + "# implementations.append(best_solution)\n", + "\n", + "# item[\"is_solved\"] = is_passing\n", + "# item[\"reflections\"] = reflections\n", + "# item[\"implementations\"] = implementations\n", + "# item[\"test_feedback\"] = test_feedback\n", + "# item[\"acc\"] = round(num_success / (idx + 1), 2)\n", + "# write_jsonl(log_path, [item], append=True)\n", + "\n", + "# print_v(f\"completed {idx+1}/{num_items}: acc = {round(num_success/(idx+1), 2)}\")" ] }, { "cell_type": "code", "execution_count": null, - "id": "9f4525b9-f63e-449d-9816-e37ca726a522", + "id": "bd8c6cc2-9b2d-4e46-8344-68d6606b3b74", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "from datasets import load_dataset\n", + "\n", + "dataset = load_dataset(\"deepmind/code_contests\", split=\"valid\")\n", + "dataset[\"validation\"]" + ] } ], "metadata": {