diff --git a/AgentReact/utils/StateElements/TodoElement.py b/AgentReact/utils/StateElements/TodoElement.py index dc79d64..303ead4 100644 --- a/AgentReact/utils/StateElements/TodoElement.py +++ b/AgentReact/utils/StateElements/TodoElement.py @@ -1,3 +1,5 @@ +import json + # Classes utilisées pour représenter des données class TodoElement(): STATE_NOT_STARTED = 0 # Sorte d'enum qui représente l'état d'une tâche @@ -7,10 +9,10 @@ class TodoElement(): name: str state: int - def __init__(self, name:str, description:str=None): + def __init__(self, name:str, description:str=None, state:int=0): self.name = name self.description = description - self.state = TodoElement.STATE_NOT_STARTED + self.state = state def __str__(self)->str: """ @@ -33,8 +35,39 @@ class TodoElement(): else: return "Inconnu" + def toJSON(self, indent:int=None)->str: # Vient de https://github.com/LJ5O/Assistant/blob/main/modules/Brain/src/Json/Types.py + """ + Exporter cet objet vers une String JSON. Permet de le passer dans le State + + Returns: + str: String sérialisable via la méthode statique TodoElement.strImport(string) + """ + return '{"name":"'+ str(self.name) +'", "desc": "'+str(self.description)+'", "state": ' + str(self.state) +'}' + + @staticmethod + def fromJSON(json_str: str|dict) -> 'InterruptPayload': + """ + Parse a JSON string to create a TodoElement instance + + Args: + json_str (str|dict): JSON string to parse, or JSON shaped dict + + Returns: + TodoElement: instance created from JSON data + """ + data = json.loads(json_str) if type(json_str) is str else json_str + + nom_ = data.get("name", "undefined") + desc_ = data.get("desc", "undefined") + state_ = data.get("state", TodoElement.STATE_NOT_STARTED) + + return TodoElement(nom_, desc_, state_) + if __name__ == "__main__": test = TodoElement("TEST tâche", "OUI") test.state = TodoElement.STATE_STARTED print(test) print([str(test)]) + print(test.toJSON()) + + print(TodoElement.fromJSON(test.toJSON())) diff --git a/AgentReact/utils/nodes.py b/AgentReact/utils/nodes.py index f34d116..3b71a08 100644 --- a/AgentReact/utils/nodes.py +++ b/AgentReact/utils/nodes.py @@ -14,6 +14,7 @@ import json from .tools import getTools, getWeeklyReportTools from .state import CustomState from .InterruptPayload import InterruptPayload +from .StateElements.TodoElement import TodoElement # Variables principales TAILLE_CONTEXTE_MAX = 20000 #charactères @@ -74,7 +75,7 @@ def LLM_central(state: CustomState): if "todo" in state.keys(): # S'il y a des TODO, je l'ajoute avant le prompt au LLM if len(state['todo'])>0: - sysmsg = SystemMessage(f"Voici la liste des tâches en cours : {str([f"{i}: {str(todo)}\n" for i,todo in enumerate(state['todo'])])}") + sysmsg = SystemMessage(f"Voici la liste des tâches en cours : {str([f"{i}: {str(TodoElement.fromJSON(todo))}\n" for i,todo in enumerate(state['todo'])])}") print(sysmsg.content) return {"messages": [model.invoke(state["messages"] + [AIMessage('.'), sysmsg])]} # AIMessage pour que Msitrail ne refuse pas la requête avec un 400 diff --git a/AgentReact/utils/state.py b/AgentReact/utils/state.py index f9085f3..f4667d5 100644 --- a/AgentReact/utils/state.py +++ b/AgentReact/utils/state.py @@ -1,11 +1,9 @@ from langgraph.graph import StateGraph, MessagesState from typing import List -from .StateElements.TodoElement import TodoElement - class CustomState(MessagesState): - todo: List[TodoElement] # Les tâches en cours + todo: List[str] # Les tâches en cours, au format JSON ragQuery: str # Requête envoyée au RAG, pour le cross-encodeur ragDocuments: List[str] # Documents retrouvés par le RAG, pour le cross-encodeur diff --git a/AgentReact/utils/tools.py b/AgentReact/utils/tools.py index 97ee9f9..be8eb6f 100644 --- a/AgentReact/utils/tools.py +++ b/AgentReact/utils/tools.py @@ -76,6 +76,7 @@ def editTodo(index:int, todoState:int, state: Annotated[dict, InjectedState], to # Erreur, l'index est trop grand return Command(update={"messages": [ToolMessage(content="Index en dehors de la liste, echec!", tool_call_id=tool_call_id)]}) + state["todo"] = [TodoElement.fromJSON(e) for e in state["todo"]] # Convertion vers de vraies instances state["todo"][index].state = todoState # Modification de l'état de cette tâche # Toutes les tâches complétées ? @@ -88,7 +89,7 @@ def editTodo(index:int, todoState:int, state: Annotated[dict, InjectedState], to if not found: state["todo"] = [] # Toutes les tâches terminées, je peux clear la TODO list du state return Command(update={ "messages": [ToolMessage(content="Réussite!", tool_call_id=tool_call_id)], - "todo": [x for x in state["todo"]] # Update du state, # medium.com/@o39joey/a-comprehensive-guide-to-langgraph-managing-agent-state-with-tools-ae932206c7d7 + "todo": [x.toJSON() for x in state["todo"]] # Update du state, # medium.com/@o39joey/a-comprehensive-guide-to-langgraph-managing-agent-state-with-tools-ae932206c7d7 }) @tool @@ -102,10 +103,11 @@ def addTodo(name:str, description:str, state: Annotated[dict, InjectedState], to """ if "todo" not in state.keys(): state["todo"] = [] + state["todo"] = [TodoElement.fromJSON(e) for e in state["todo"]] # Convertion vers de vraies instances state["todo"].append(TodoElement(name, description)) return Command(update={ "messages": [ToolMessage(content="Réussite!", tool_call_id=tool_call_id)], - "todo": [x for x in state["todo"]] # Update du state, # medium.com/@o39joey/a-comprehensive-guide-to-langgraph-managing-agent-state-with-tools-ae932206c7d7 + "todo": [x.toJSON() for x in state["todo"]] # Update du state, # medium.com/@o39joey/a-comprehensive-guide-to-langgraph-managing-agent-state-with-tools-ae932206c7d7 }) @tool