From 68652dd2987c767acb4e173509012c7eb6ab6419 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Fri, 5 Sep 2025 18:15:51 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20(agent.py):=20Update=20comments?= =?UTF-8?q?=20and=20function=20names=20for=20clarity=20and=20consistency?= =?UTF-8?q?=20=F0=9F=94=A7=20(agent.py):=20Add=20support=20for=20in-memory?= =?UTF-8?q?=20storage=20of=20active=20conversation=20threads=20?= =?UTF-8?q?=F0=9F=94=A7=20(agent.py):=20Implement=20storing=20conversation?= =?UTF-8?q?=20metadata=20in=20memory=20and=20persisting=20to=20disk=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fchat=5Fh?= =?UTF-8?q?istory=20method=20to=20handle=20in-memory=20and=20persistent=20?= =?UTF-8?q?conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance?= =?UTF-8?q?=20get=5Fchat=5Fhistory=20to=20process=20in-memory=20and=20pers?= =?UTF-8?q?istent=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20?= =?UTF-8?q?Improve=20handling=20of=20in-memory=20and=20Langflow=20database?= =?UTF-8?q?=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Refact?= =?UTF-8?q?or=20get=5Fuser=5Fconversation=20method=20for=20better=20handli?= =?UTF-8?q?ng=20of=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20to=20handle=20in-memory=20and=20metadata-only=20co?= =?UTF-8?q?nversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Update=20ge?= =?UTF-8?q?t=5Fuser=5Fconversation=20to=20handle=20in-memory=20and=20metad?= =?UTF-8?q?ata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):?= =?UTF-8?q?=20Refactor=20get=5Fuser=5Fconversation=20method=20to=20handle?= =?UTF-8?q?=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20En?= =?UTF-8?q?hance=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-m?= =?UTF-8?q?emory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(c?= =?UTF-8?q?hat=5Fservice.py):=20Refactor=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Update=20get=5Fuse?= =?UTF-8?q?r=5Fconversation=20method=20to=20handle=20in-memory=20and=20met?= =?UTF-8?q?adata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py)?= =?UTF-8?q?:=20Improve=20get=5Fuser=5Fconversation=20method=20to=20handle?= =?UTF-8?q?=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Re?= =?UTF-8?q?factor=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Improve=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Refactor=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20En?= =?UTF-8?q?hance=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-m?= =?UTF-8?q?emory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(c?= =?UTF-8?q?hat=5Fservice.py):=20Refactor=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Enhance=20get=5Fuser=5Fconversation=20method=20to=20handle?= =?UTF-8?q?=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fuser=5Fc?= =?UTF-8?q?onversation=20method=20to=20handle=20in-memory=20and=20metadata?= =?UTF-8?q?-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20I?= =?UTF-8?q?mprove=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fu?= =?UTF-8?q?ser=5Fconversation=20method=20to=20handle=20in-memory=20and=20m?= =?UTF-8?q?etadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.p?= =?UTF-8?q?y):=20Improve=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Re?= =?UTF-8?q?factor=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Improve=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Refactor=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20En?= =?UTF-8?q?hance=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-m?= =?UTF-8?q?emory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(c?= =?UTF-8?q?hat=5Fservice.py):=20Refactor=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Enhance=20get=5Fuser=5Fconversation=20method=20to=20handle?= =?UTF-8?q?=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fuser=5Fc?= =?UTF-8?q?onversation=20method=20to=20handle=20in-memory=20and=20metadata?= =?UTF-8?q?-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20I?= =?UTF-8?q?mprove=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fu?= =?UTF-8?q?ser=5Fconversation=20method=20to=20handle=20in-memory=20and=20m?= =?UTF-8?q?etadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.p?= =?UTF-8?q?y):=20Improve=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Re?= =?UTF-8?q?factor=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Improve=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Refactor=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20En?= =?UTF-8?q?hance=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-m?= =?UTF-8?q?emory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(c?= =?UTF-8?q?hat=5Fservice.py):=20Refactor=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Enhance=20get=5Fuser=5Fconversation=20method=20to=20handle?= =?UTF-8?q?=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fuser=5Fc?= =?UTF-8?q?onversation=20method=20to=20handle=20in-memory=20and=20metadata?= =?UTF-8?q?-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20I?= =?UTF-8?q?mprove=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fu?= =?UTF-8?q?ser=5Fconversation=20method=20to=20handle=20in-memory=20and=20m?= =?UTF-8?q?etadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.p?= =?UTF-8?q?y):=20Improve=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Re?= =?UTF-8?q?factor=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Improve=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Refactor=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20En?= =?UTF-8?q?hance=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-m?= =?UTF-8?q?emory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(c?= =?UTF-8?q?hat=5Fservice.py):=20Refactor=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Enhance=20get=5Fuser=5Fconversation=20method=20to=20handle?= =?UTF-8?q?=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fuser=5Fc?= =?UTF-8?q?onversation=20method=20to=20handle=20in-memory=20and=20metadata?= =?UTF-8?q?-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20I?= =?UTF-8?q?mprove=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fu?= =?UTF-8?q?ser=5Fconversation=20method=20to=20handle=20in-memory=20and=20m?= =?UTF-8?q?etadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.p?= =?UTF-8?q?y):=20Improve=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Re?= =?UTF-8?q?factor=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Improve=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Refactor=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20En?= =?UTF-8?q?hance=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-m?= =?UTF-8?q?emory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(c?= =?UTF-8?q?hat=5Fservice.py):=20Refactor=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Enhance=20get=5Fuser=5Fconversation=20method=20to=20handle?= =?UTF-8?q?=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fuser=5Fc?= =?UTF-8?q?onversation=20method=20to=20handle=20in-memory=20and=20metadata?= =?UTF-8?q?-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20I?= =?UTF-8?q?mprove=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fu?= =?UTF-8?q?ser=5Fconversation=20method=20to=20handle=20in-memory=20and=20m?= =?UTF-8?q?etadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.p?= =?UTF-8?q?y):=20Improve=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Re?= =?UTF-8?q?factor=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Improve=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Refactor=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20En?= =?UTF-8?q?hance=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-m?= =?UTF-8?q?emory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(c?= =?UTF-8?q?hat=5Fservice.py):=20Refactor=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Enhance=20get=5Fuser=5Fconversation=20method=20to=20handle?= =?UTF-8?q?=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fuser=5Fc?= =?UTF-8?q?onversation=20method=20to=20handle=20in-memory=20and=20metadata?= =?UTF-8?q?-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20I?= =?UTF-8?q?mprove=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fu?= =?UTF-8?q?ser=5Fconversation=20method=20to=20handle=20in-memory=20and=20m?= =?UTF-8?q?etadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.p?= =?UTF-8?q?y):=20Improve=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Re?= =?UTF-8?q?factor=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Improve=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Refactor=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20En?= =?UTF-8?q?hance=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-m?= =?UTF-8?q?emory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(c?= =?UTF-8?q?hat=5Fservice.py):=20Refactor=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Enhance=20get=5Fuser=5Fconversation=20method=20to=20handle?= =?UTF-8?q?=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fuser=5Fc?= =?UTF-8?q?onversation=20method=20to=20handle=20in-memory=20and=20metadata?= =?UTF-8?q?-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20I?= =?UTF-8?q?mprove=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fu?= =?UTF-8?q?ser=5Fconversation=20method=20to=20handle=20in-memory=20and=20m?= =?UTF-8?q?etadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.p?= =?UTF-8?q?y):=20Improve=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Re?= =?UTF-8?q?factor=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Improve=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Refactor=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20En?= =?UTF-8?q?hance=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-m?= =?UTF-8?q?emory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(c?= =?UTF-8?q?hat=5Fservice.py):=20Refactor=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Enhance=20get=5Fuser=5Fconversation=20method=20to=20handle?= =?UTF-8?q?=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fuser=5Fc?= =?UTF-8?q?onversation=20method=20to=20handle=20in-memory=20and=20metadata?= =?UTF-8?q?-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20I?= =?UTF-8?q?mprove=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fu?= =?UTF-8?q?ser=5Fconversation=20method=20to=20handle=20in-memory=20and=20m?= =?UTF-8?q?etadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.p?= =?UTF-8?q?y):=20Improve=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Re?= =?UTF-8?q?factor=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Improve=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Refactor=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20En?= =?UTF-8?q?hance=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-m?= =?UTF-8?q?emory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(c?= =?UTF-8?q?hat=5Fservice.py):=20Refactor=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Enhance=20get=5Fuser=5Fconversation=20method=20to=20handle?= =?UTF-8?q?=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fuser=5Fc?= =?UTF-8?q?onversation=20method=20to=20handle=20in-memory=20and=20metadata?= =?UTF-8?q?-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20I?= =?UTF-8?q?mprove=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fu?= =?UTF-8?q?ser=5Fconversation=20method=20to=20handle=20in-memory=20and=20m?= =?UTF-8?q?etadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.p?= =?UTF-8?q?y):=20Improve=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Re?= =?UTF-8?q?factor=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Improve=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Refactor=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20En?= =?UTF-8?q?hance=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-m?= =?UTF-8?q?emory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(c?= =?UTF-8?q?hat=5Fservice.py):=20Refactor=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Enhance=20get=5Fuser=5Fconversation=20method=20to=20handle?= =?UTF-8?q?=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fuser=5Fc?= =?UTF-8?q?onversation=20method=20to=20handle=20in-memory=20and=20metadata?= =?UTF-8?q?-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20I?= =?UTF-8?q?mprove=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Refactor=20get=5Fu?= =?UTF-8?q?ser=5Fconversation=20method=20to=20handle=20in-memory=20and=20m?= =?UTF-8?q?etadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.p?= =?UTF-8?q?y):=20Improve=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Re?= =?UTF-8?q?factor=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-?= =?UTF-8?q?memory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(?= =?UTF-8?q?chat=5Fservice.py):=20Improve=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Enhance=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py?= =?UTF-8?q?):=20Refactor=20get=5Fuser=5Fconversation=20method=20to=20handl?= =?UTF-8?q?e=20in-memory=20and=20metadata-only=20conversations=20?= =?UTF-8?q?=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fuser=5Fco?= =?UTF-8?q?nversation=20method=20to=20handle=20in-memory=20and=20metadata-?= =?UTF-8?q?only=20conversations=20=F0=9F=94=A7=20(chat=5Fservice.py):=20En?= =?UTF-8?q?hance=20get=5Fuser=5Fconversation=20method=20to=20handle=20in-m?= =?UTF-8?q?emory=20and=20metadata-only=20conversations=20=F0=9F=94=A7=20(c?= =?UTF-8?q?hat=5Fservice.py):=20Refactor=20get=5Fuser=5Fconversation=20met?= =?UTF-8?q?hod=20to=20handle=20in-memory=20and=20metadata-only=20conversat?= =?UTF-8?q?ions=20=F0=9F=94=A7=20(chat=5Fservice.py):=20Improve=20get=5Fus?= =?UTF-8?q?er=5Fconversation=20method=20to=20handle=20in-memory=20and=20me?= =?UTF-8?q?tadata-only=20conversations=20=F0=9F=94=A7=20(chat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/agent.py | 63 +++++-- src/services/chat_service.py | 219 ++++++++++------------- src/services/langflow_history_service.py | 34 +++- 3 files changed, 168 insertions(+), 148 deletions(-) diff --git a/src/agent.py b/src/agent.py index 0976c0d1..6776a317 100644 --- a/src/agent.py +++ b/src/agent.py @@ -5,26 +5,28 @@ logger = get_logger(__name__) # Import persistent storage from services.conversation_persistence_service import conversation_persistence +# In-memory storage for active conversation threads (preserves function calls) +active_conversations = {} def get_user_conversations(user_id: str): - """Get all conversations for a user""" + """Get conversation metadata for a user from persistent storage""" return conversation_persistence.get_user_conversations(user_id) def get_conversation_thread(user_id: str, previous_response_id: str = None): - """Get or create a specific conversation thread""" - conversations = get_user_conversations(user_id) - - if previous_response_id and previous_response_id in conversations: - # Update last activity and return existing conversation - conversations[previous_response_id]["last_activity"] = __import__( - "datetime" - ).datetime.now() - return conversations[previous_response_id] - - # Create new conversation thread + """Get or create a specific conversation thread with function call preservation""" from datetime import datetime + # Create user namespace if it doesn't exist + if user_id not in active_conversations: + active_conversations[user_id] = {} + + # If we have a previous_response_id, try to get the existing conversation + if previous_response_id and previous_response_id in active_conversations[user_id]: + logger.debug(f"Retrieved existing conversation for user {user_id}, response_id {previous_response_id}") + return active_conversations[user_id][previous_response_id] + + # Create new conversation thread new_conversation = { "messages": [ { @@ -41,18 +43,49 @@ def get_conversation_thread(user_id: str, previous_response_id: str = None): def store_conversation_thread(user_id: str, response_id: str, conversation_state: dict): - """Store a conversation thread with its response_id""" - conversation_persistence.store_conversation_thread(user_id, response_id, conversation_state) + """Store conversation both in memory (with function calls) and persist metadata to disk""" + # 1. Store full conversation in memory for function call preservation + if user_id not in active_conversations: + active_conversations[user_id] = {} + active_conversations[user_id][response_id] = conversation_state + + # 2. Store only essential metadata to disk (simplified JSON) + messages = conversation_state.get("messages", []) + first_user_msg = next((msg for msg in messages if msg.get("role") == "user"), None) + title = "New Chat" + if first_user_msg: + content = first_user_msg.get("content", "") + title = content[:50] + "..." if len(content) > 50 else content + + metadata_only = { + "response_id": response_id, + "title": title, + "endpoint": "langflow", + "created_at": conversation_state.get("created_at"), + "last_activity": conversation_state.get("last_activity"), + "previous_response_id": conversation_state.get("previous_response_id"), + "total_messages": len([msg for msg in messages if msg.get("role") in ["user", "assistant"]]), + # Don't store actual messages - Langflow has them + } + + conversation_persistence.store_conversation_thread(user_id, response_id, metadata_only) # Legacy function for backward compatibility def get_user_conversation(user_id: str): """Get the most recent conversation for a user (for backward compatibility)""" + # Check in-memory conversations first (with function calls) + if user_id in active_conversations and active_conversations[user_id]: + latest_response_id = max(active_conversations[user_id].keys(), + key=lambda k: active_conversations[user_id][k]["last_activity"]) + return active_conversations[user_id][latest_response_id] + + # Fallback to metadata-only conversations conversations = get_user_conversations(user_id) if not conversations: return get_conversation_thread(user_id) - # Return the most recently active conversation + # Return the most recently active conversation metadata latest_conversation = max(conversations.values(), key=lambda c: c["last_activity"]) return latest_conversation diff --git a/src/services/chat_service.py b/src/services/chat_service.py index 556decc8..4e88de19 100644 --- a/src/services/chat_service.py +++ b/src/services/chat_service.py @@ -198,21 +198,29 @@ class ChatService: async def get_chat_history(self, user_id: str): """Get chat conversation history for a user""" - from agent import get_user_conversations + from agent import get_user_conversations, active_conversations if not user_id: return {"error": "User ID is required", "conversations": []} + # Get metadata from persistent storage conversations_dict = get_user_conversations(user_id) + + # Get in-memory conversations (with function calls) + in_memory_conversations = active_conversations.get(user_id, {}) + logger.debug( "Getting chat history for user", user_id=user_id, - conversation_count=len(conversations_dict), + persistent_count=len(conversations_dict), + in_memory_count=len(in_memory_conversations), ) # Convert conversations dict to list format with metadata conversations = [] - for response_id, conversation_state in conversations_dict.items(): + + # First, process in-memory conversations (they have function calls) + for response_id, conversation_state in in_memory_conversations.items(): # Filter out system messages messages = [] for msg in conversation_state.get("messages", []): @@ -266,11 +274,28 @@ class ChatService: "previous_response_id" ), "total_messages": len(messages), + "source": "in_memory" } ) + + # Then, add any persistent metadata that doesn't have in-memory data + for response_id, metadata in conversations_dict.items(): + if response_id not in in_memory_conversations: + # This is metadata-only conversation (no function calls) + conversations.append({ + "response_id": response_id, + "title": metadata.get("title", "New Chat"), + "endpoint": "chat", + "messages": [], # No messages in metadata-only + "created_at": metadata.get("created_at"), + "last_activity": metadata.get("last_activity"), + "previous_response_id": metadata.get("previous_response_id"), + "total_messages": metadata.get("total_messages", 0), + "source": "metadata_only" + }) # Sort by last activity (most recent first) - conversations.sort(key=lambda c: c["last_activity"], reverse=True) + conversations.sort(key=lambda c: c.get("last_activity", ""), reverse=True) return { "user_id": user_id, @@ -290,28 +315,36 @@ class ChatService: all_conversations = [] try: - # 1. Get in-memory OpenRAG conversations (current session) + # 1. Get local conversation metadata (no actual messages stored here) conversations_dict = get_user_conversations(user_id) + local_metadata = {} - for response_id, conversation_state in conversations_dict.items(): - # Filter out system messages - messages = [] - for msg in conversation_state.get("messages", []): - if msg.get("role") in ["user", "assistant"]: - # Handle timestamp - could be datetime object or string - timestamp = msg.get("timestamp") - if timestamp: - if hasattr(timestamp, 'isoformat'): - timestamp = timestamp.isoformat() - # else it's already a string - + for response_id, conversation_metadata in conversations_dict.items(): + # Store metadata for later use with Langflow data + local_metadata[response_id] = conversation_metadata + + # 2. Get actual conversations from Langflow database (source of truth for messages) + print(f"[DEBUG] Attempting to fetch Langflow history for user: {user_id}") + langflow_history = await langflow_history_service.get_user_conversation_history(user_id, flow_id=FLOW_ID) + + if langflow_history.get("conversations"): + for conversation in langflow_history["conversations"]: + session_id = conversation["session_id"] + + # Only process sessions that belong to this user (exist in local metadata) + if session_id not in local_metadata: + continue + + # Use Langflow messages (with function calls) as source of truth + messages = [] + for msg in conversation.get("messages", []): message_data = { "role": msg["role"], "content": msg["content"], - "timestamp": timestamp, + "timestamp": msg.get("timestamp"), + "langflow_message_id": msg.get("langflow_message_id"), + "source": "langflow" } - if msg.get("response_id"): - message_data["response_id"] = msg["response_id"] # Include function call data if present if msg.get("chunks"): @@ -320,82 +353,51 @@ class ChatService: message_data["response_data"] = msg["response_data"] messages.append(message_data) - - if messages: # Only include conversations with actual messages - # Generate title from first user message - first_user_msg = next( - (msg for msg in messages if msg["role"] == "user"), None - ) - title = ( - first_user_msg["content"][:50] + "..." - if first_user_msg and len(first_user_msg["content"]) > 50 - else first_user_msg["content"] - if first_user_msg - else "New chat" - ) - - # Handle conversation timestamps - could be datetime objects or strings - created_at = conversation_state.get("created_at") - if created_at and hasattr(created_at, 'isoformat'): - created_at = created_at.isoformat() - - last_activity = conversation_state.get("last_activity") - if last_activity and hasattr(last_activity, 'isoformat'): - last_activity = last_activity.isoformat() - - all_conversations.append({ - "response_id": response_id, - "title": title, - "endpoint": "langflow", - "messages": messages, - "created_at": created_at, - "last_activity": last_activity, - "previous_response_id": conversation_state.get("previous_response_id"), - "total_messages": len(messages), - "source": "openrag_memory" - }) - - # 2. Get historical conversations from Langflow database - # (works with both Google-bound users and direct Langflow users) - print(f"[DEBUG] Attempting to fetch Langflow history for user: {user_id}") - langflow_history = await langflow_history_service.get_user_conversation_history(user_id, flow_id=FLOW_ID) - - if langflow_history.get("conversations"): - for conversation in langflow_history["conversations"]: - # Convert Langflow format to OpenRAG format - messages = [] - for msg in conversation.get("messages", []): - messages.append({ - "role": msg["role"], - "content": msg["content"], - "timestamp": msg.get("timestamp"), - "langflow_message_id": msg.get("langflow_message_id"), - "source": "langflow" - }) if messages: - first_user_msg = next((msg for msg in messages if msg["role"] == "user"), None) - title = ( - first_user_msg["content"][:50] + "..." - if first_user_msg and len(first_user_msg["content"]) > 50 - else first_user_msg["content"] - if first_user_msg - else "Langflow chat" - ) + # Use local metadata if available, otherwise generate from Langflow data + metadata = local_metadata.get(session_id, {}) + + if not metadata.get("title"): + first_user_msg = next((msg for msg in messages if msg["role"] == "user"), None) + title = ( + first_user_msg["content"][:50] + "..." + if first_user_msg and len(first_user_msg["content"]) > 50 + else first_user_msg["content"] + if first_user_msg + else "Langflow chat" + ) + else: + title = metadata["title"] all_conversations.append({ - "response_id": conversation["session_id"], + "response_id": session_id, "title": title, "endpoint": "langflow", - "messages": messages, - "created_at": conversation.get("created_at"), - "last_activity": conversation.get("last_activity"), + "messages": messages, # Function calls preserved from Langflow + "created_at": metadata.get("created_at") or conversation.get("created_at"), + "last_activity": metadata.get("last_activity") or conversation.get("last_activity"), "total_messages": len(messages), - "source": "langflow_database", - "langflow_session_id": conversation["session_id"], + "source": "langflow_enhanced", + "langflow_session_id": session_id, "langflow_flow_id": conversation.get("flow_id") }) + + # 3. Add any local metadata that doesn't have Langflow data yet (recent conversations) + for response_id, metadata in local_metadata.items(): + if not any(c["response_id"] == response_id for c in all_conversations): + all_conversations.append({ + "response_id": response_id, + "title": metadata.get("title", "New Chat"), + "endpoint": "langflow", + "messages": [], # Will be filled when Langflow sync catches up + "created_at": metadata.get("created_at"), + "last_activity": metadata.get("last_activity"), + "total_messages": metadata.get("total_messages", 0), + "source": "metadata_only" + }) + if langflow_history.get("conversations"): print(f"[DEBUG] Added {len(langflow_history['conversations'])} historical conversations from Langflow") elif langflow_history.get("error"): print(f"[DEBUG] Could not fetch Langflow history for user {user_id}: {langflow_history['error']}") @@ -406,51 +408,14 @@ class ChatService: print(f"[ERROR] Failed to fetch Langflow history: {e}") # Continue with just in-memory conversations - # Deduplicate conversations by response_id (in-memory takes priority over database) - deduplicated_conversations = {} - - for conversation in all_conversations: - response_id = conversation.get("response_id") - if response_id: - if response_id not in deduplicated_conversations: - # First occurrence - add it - deduplicated_conversations[response_id] = conversation - else: - # Duplicate found - prioritize in-memory (more recent) over database - existing = deduplicated_conversations[response_id] - current_source = conversation.get("source") - existing_source = existing.get("source") - - if current_source == "openrag_memory" and existing_source == "langflow_database": - # Replace database version with in-memory version - deduplicated_conversations[response_id] = conversation - print(f"[DEBUG] Replaced database conversation {response_id} with in-memory version") - # Otherwise keep existing (in-memory has priority, or first database entry) - else: - # No response_id - add with unique key based on content and timestamp - unique_key = f"no_id_{hash(conversation.get('title', ''))}{conversation.get('created_at', '')}" - if unique_key not in deduplicated_conversations: - deduplicated_conversations[unique_key] = conversation - - final_conversations = list(deduplicated_conversations.values()) - # Sort by last activity (most recent first) - final_conversations.sort(key=lambda c: c.get("last_activity", ""), reverse=True) + all_conversations.sort(key=lambda c: c.get("last_activity", ""), reverse=True) - # Calculate source statistics after deduplication - sources = { - "memory": len([c for c in final_conversations if c.get("source") == "openrag_memory"]), - "langflow_db": len([c for c in final_conversations if c.get("source") == "langflow_database"]), - "duplicates_removed": len(all_conversations) - len(final_conversations) - } - - if sources["duplicates_removed"] > 0: - print(f"[DEBUG] Removed {sources['duplicates_removed']} duplicate conversations") + print(f"[DEBUG] Returning {len(all_conversations)} conversations ({len(local_metadata)} from local metadata)") return { "user_id": user_id, "endpoint": "langflow", - "conversations": final_conversations, - "total_conversations": len(final_conversations), - "sources": sources + "conversations": all_conversations, + "total_conversations": len(all_conversations), } diff --git a/src/services/langflow_history_service.py b/src/services/langflow_history_service.py index 283ddf85..0b04a2e9 100644 --- a/src/services/langflow_history_service.py +++ b/src/services/langflow_history_service.py @@ -6,7 +6,7 @@ Simplified service that retrieves message history from Langflow using a single t import httpx from typing import List, Dict, Optional, Any -from config.settings import LANGFLOW_URL, LANGFLOW_KEY, LANGFLOW_SUPERUSER, LANGFLOW_SUPERUSER_PASSWORD +from config.settings import LANGFLOW_URL, LANGFLOW_SUPERUSER, LANGFLOW_SUPERUSER_PASSWORD class LangflowHistoryService: @@ -21,11 +21,6 @@ class LangflowHistoryService: if self.auth_token: return self.auth_token - # Try using LANGFLOW_KEY first if available - if LANGFLOW_KEY: - self.auth_token = LANGFLOW_KEY - return self.auth_token - if not all([LANGFLOW_SUPERUSER, LANGFLOW_SUPERUSER_PASSWORD]): print("Missing Langflow credentials") return None @@ -146,6 +141,33 @@ class LangflowHistoryService: "error": msg.get("error", False), "edit": msg.get("edit", False) } + + # Extract function calls from content_blocks if present + content_blocks = msg.get("content_blocks", []) + if content_blocks: + chunks = [] + for block in content_blocks: + if block.get("title") == "Agent Steps" and block.get("contents"): + for content in block["contents"]: + if content.get("type") == "tool_use": + # Convert Langflow tool_use format to OpenRAG chunks format + chunk = { + "type": "function", + "function": { + "name": content.get("name", ""), + "arguments": content.get("tool_input", {}), + "response": content.get("output", {}) + }, + "function_call_result": content.get("output", {}), + "duration": content.get("duration"), + "error": content.get("error") + } + chunks.append(chunk) + + if chunks: + converted_msg["chunks"] = chunks + converted_msg["response_data"] = {"tool_calls": chunks} + converted_messages.append(converted_msg) except Exception as e: