11import base64
22import re
33import traceback
4- import uuid
54from io import BytesIO
65from os import getenv
76from typing import Optional
7+ from uuid import UUID , uuid4
88
99from codeboxapi import CodeBox # type: ignore
1010from codeboxapi .schema import CodeBoxOutput # type: ignore
1717from langchain .chat_models import AzureChatOpenAI , ChatAnthropic , ChatOpenAI
1818from langchain .chat_models .base import BaseChatModel
1919from langchain .memory import ConversationBufferMemory
20+ from langchain .memory .chat_message_histories import (
21+ ChatMessageHistory ,
22+ PostgresChatMessageHistory ,
23+ RedisChatMessageHistory ,
24+ )
2025from langchain .prompts .chat import MessagesPlaceholder
21- from langchain .schema . language_model import BaseLanguageModel
26+ from langchain .schema import BaseChatMessageHistory , BaseLanguageModel
2227from langchain .tools import BaseTool , StructuredTool
2328
2429from codeinterpreterapi .agents import OpenAIFunctionsAgent
2833 get_file_modifications ,
2934 remove_download_link ,
3035)
36+ from codeinterpreterapi .chat_history import CodeBoxChatMessageHistory
3137from codeinterpreterapi .config import settings
3238from codeinterpreterapi .parser import CodeAgentOutputParser , CodeChatAgentOutputParser
3339from codeinterpreterapi .prompts import code_interpreter_system_message
@@ -47,20 +53,35 @@ def __init__(
4753 additional_tools : list [BaseTool ] = [],
4854 ** kwargs ,
4955 ) -> None :
50- self .codebox = CodeBox (** kwargs )
56+ self .codebox = CodeBox ()
5157 self .verbose = kwargs .get ("verbose" , settings .VERBOSE )
5258 self .tools : list [BaseTool ] = self ._tools (additional_tools )
5359 self .llm : BaseLanguageModel = llm or self ._choose_llm (** kwargs )
54- self .agent_executor : AgentExecutor = self . _agent_executor ()
60+ self .agent_executor : Optional [ AgentExecutor ] = None
5561 self .input_files : list [File ] = []
5662 self .output_files : list [File ] = []
5763 self .code_log : list [tuple [str , str ]] = []
5864
65+ @classmethod
66+ def from_id (cls , session_id : UUID , ** kwargs ) -> "CodeInterpreterSession" :
67+ session = cls (** kwargs )
68+ session .codebox = CodeBox .from_id (session_id )
69+ session .agent_executor = session ._agent_executor ()
70+ return session
71+
72+ @property
73+ def session_id (self ) -> Optional [UUID ]:
74+ return self .codebox .session_id
75+
5976 def start (self ) -> SessionStatus :
60- return SessionStatus .from_codebox_status (self .codebox .start ())
77+ status = SessionStatus .from_codebox_status (self .codebox .start ())
78+ self .agent_executor = self ._agent_executor ()
79+ return status
6180
6281 async def astart (self ) -> SessionStatus :
63- return SessionStatus .from_codebox_status (await self .codebox .astart ())
82+ status = SessionStatus .from_codebox_status (await self .codebox .astart ())
83+ self .agent_executor = self ._agent_executor ()
84+ return status
6485
6586 def _tools (self , additional_tools : list [BaseTool ]) -> list [BaseTool ]:
6687 return additional_tools + [
@@ -108,15 +129,15 @@ def _choose_llm(
108129 openai_api_key = openai_api_key ,
109130 max_retries = 3 ,
110131 request_timeout = 60 * 3 ,
111- )
132+ ) # type: ignore
112133 else :
113134 return ChatOpenAI (
114135 temperature = 0.03 ,
115136 model = model ,
116137 openai_api_key = openai_api_key ,
117138 max_retries = 3 ,
118139 request_timeout = 60 * 3 ,
119- )
140+ ) # type: ignore
120141 elif "claude" in model :
121142 return ChatAnthropic (model = model )
122143 else :
@@ -148,14 +169,33 @@ def _choose_agent(self) -> BaseSingleActionAgent:
148169 )
149170 )
150171
172+ def _history_backend (self ) -> BaseChatMessageHistory :
173+ return (
174+ CodeBoxChatMessageHistory (codebox = self .codebox )
175+ if settings .HISTORY_BACKEND == "codebox"
176+ else RedisChatMessageHistory (
177+ session_id = str (self .session_id ),
178+ url = settings .REDIS_URL ,
179+ )
180+ if settings .HISTORY_BACKEND == "redis"
181+ else PostgresChatMessageHistory (
182+ session_id = str (self .session_id ),
183+ connection_string = settings .POSTGRES_URL ,
184+ )
185+ if settings .HISTORY_BACKEND == "postgres"
186+ else ChatMessageHistory ()
187+ )
188+
151189 def _agent_executor (self ) -> AgentExecutor :
152190 return AgentExecutor .from_agent_and_tools (
153191 agent = self ._choose_agent (),
154192 max_iterations = 9 ,
155193 tools = self .tools ,
156194 verbose = self .verbose ,
157195 memory = ConversationBufferMemory (
158- memory_key = "chat_history" , return_messages = True
196+ memory_key = "chat_history" ,
197+ return_messages = True ,
198+ chat_memory = self ._history_backend (),
159199 ),
160200 )
161201
@@ -178,7 +218,7 @@ def _run_handler(self, code: str):
178218 raise TypeError ("Expected output.content to be a string." )
179219
180220 if output .type == "image/png" :
181- filename = f"image-{ uuid . uuid4 ()} .png"
221+ filename = f"image-{ uuid4 ()} .png"
182222 file_buffer = BytesIO (base64 .b64decode (output .content ))
183223 file_buffer .name = filename
184224 self .output_files .append (File (name = filename , content = file_buffer .read ()))
@@ -225,7 +265,7 @@ async def _arun_handler(self, code: str):
225265 raise TypeError ("Expected output.content to be a string." )
226266
227267 if output .type == "image/png" :
228- filename = f"image-{ uuid . uuid4 ()} .png"
268+ filename = f"image-{ uuid4 ()} .png"
229269 file_buffer = BytesIO (base64 .b64decode (output .content ))
230270 file_buffer .name = filename
231271 self .output_files .append (File (name = filename , content = file_buffer .read ()))
@@ -349,6 +389,7 @@ def generate_response_sync(
349389 user_request = UserRequest (content = user_msg , files = files )
350390 try :
351391 self ._input_handler (user_request )
392+ assert self .agent_executor , "Session not initialized."
352393 response = self .agent_executor .run (input = user_request .content )
353394 return self ._output_handler (response )
354395 except Exception as e :
@@ -392,6 +433,7 @@ async def agenerate_response(
392433 user_request = UserRequest (content = user_msg , files = files )
393434 try :
394435 await self ._ainput_handler (user_request )
436+ assert self .agent_executor , "Session not initialized."
395437 response = await self .agent_executor .arun (input = user_request .content )
396438 return await self ._aoutput_handler (response )
397439 except Exception as e :
0 commit comments