99 from aicore .config import Config
1010 from aicore .llm import Llm , LlmConfig
1111 from aicore .models import AuthenticationError , ModelError
12- from aicore .const import STREAM_END_TOKEN , STREAM_START_TOKEN #, REASONING_START_TOKEN, REASONING_STOP_TOKEN
13- from codetide .agents .tide .ui .utils import process_thread , run_concurrent_tasks , send_reasoning_msg
12+ from aicore .const import STREAM_END_TOKEN , STREAM_START_TOKEN #, REASONING_START_TOKEN, REASONING_STOP_TOKEN
13+ from codetide .agents .tide .ui .utils import process_thread , run_concurrent_tasks , send_reasoning_msg , check_docker , launch_postgres
1414 from codetide .agents .tide .ui .stream_processor import StreamProcessor , MarkerConfig
1515 from codetide .agents .tide .ui .defaults import AGENT_TIDE_PORT , STARTERS
1616 from codetide .agents .tide .ui .agent_tide_ui import AgentTideUi
2424except ImportError as e :
2525 raise ImportError (
2626 "The 'codetide.agents' module requires the 'aicore' and 'chainlit' packages. "
27- "Install it with: pip install codetide[agents -ui]"
27+ "Install it with: pip install codetide[aasygents -ui]"
2828 ) from e
2929
3030from codetide .agents .tide .ui .defaults import AICORE_CONFIG_EXAMPLE , EXCEPTION_MESSAGE , MISSING_CONFIG_MESSAGE
3131from codetide .agents .tide .defaults import DEFAULT_AGENT_TIDE_LLM_CONFIG_PATH
3232from codetide .core .defaults import DEFAULT_ENCODING
33+ from dotenv import get_key , load_dotenv , set_key
3334from codetide .agents .data_layer import init_db
3435from ulid import ulid
3536import argparse
3637import getpass
3738import asyncio
39+ import secrets
40+ import string
3841import json
3942import yaml
4043import time
4144
42- @cl .password_auth_callback
43- def auth ():
44- username = getpass .getuser ()
45- return cl .User (identifier = username , display_name = username )
45+ if check_docker and os .getenv ("AGENTTIDE_PG_CONN_STR" ) is not None :
46+ @cl .password_auth_callback
47+ def auth ():
48+ username = getpass .getuser ()
49+ return cl .User (identifier = username , display_name = username )
4650
47- @cl .data_layer
48- def get_data_layer ():
49- return SQLAlchemyDataLayer (conninfo = f"sqlite+aiosqlite:/// { os .environ [ 'CHAINLIT_APP_ROOT' ] } /database.db" )
51+ @cl .data_layer
52+ def get_data_layer ():
53+ return SQLAlchemyDataLayer (conninfo = os .getenv ( "AGENTTIDE_PG_CONN_STR" ) )
5054
5155@cl .on_settings_update
5256async def setup_llm_config (settings ):
@@ -442,9 +446,18 @@ async def agent_loop(message: Optional[cl.Message]=None, codeIdentifiers: Option
442446 chat_history .append ({"role" : "user" , "content" : feedback })
443447 await agent_loop (agent_tide_ui = agent_tide_ui )
444448
445- # def generate_temp_password(length=16):
446- # characters = string.ascii_letters + string.digits + string.punctuation
447- # return ''.join(secrets.choice(characters) for _ in range(length))
449+ def generate_password (length : int = 16 ) -> str :
450+ """
451+ Generate a secure random password.
452+ Works on Linux, macOS, and Windows.
453+ """
454+ if password := get_key (Path (os .environ ['CHAINLIT_APP_ROOT' ]) / ".env" , "AGENTTDE_PG_PASSWORD" ):
455+ return password
456+
457+ safe_chars = string .ascii_letters + string .digits + '-_@#$%^&*+=[]{}|:;<>?'
458+ password = '' .join (secrets .choice (safe_chars ) for _ in range (length ))
459+ set_key (Path (os .environ ['CHAINLIT_APP_ROOT' ]) / ".env" ,"AGENTTDE_PG_PASSWORD" , password )
460+ return password
448461
449462def serve (
450463 host = None ,
@@ -454,14 +467,7 @@ def serve(
454467 ssl_keyfile = None ,
455468 ws_per_message_deflate = "true" ,
456469 ws_protocol = "auto"
457- ):
458- username = getpass .getuser ()
459- GREEN = "\033 [92m"
460- RESET = "\033 [0m"
461-
462- print (f"\n { GREEN } Your chainlit username is `{ username } `{ RESET } \n " )
463-
464-
470+ ):
465471 # if not os.getenv("_PASSWORD"):
466472 # temp_password = generate_temp_password()
467473 # os.environ["_PASSWORD"] = temp_password
@@ -513,10 +519,33 @@ def main():
513519 parser .add_argument ("--config-path" , type = str , default = DEFAULT_AGENT_TIDE_LLM_CONFIG_PATH , help = "Path to the config file" )
514520 args = parser .parse_args ()
515521
522+ load_dotenv ()
516523 os .environ ["AGENT_TIDE_PROJECT_PATH" ] = str (Path (args .project_path ))
517524 os .environ ["AGENT_TIDE_CONFIG_PATH" ] = str (Path (args .project_path ) / args .config_path )
525+
526+ load_dotenv ()
527+ username = getpass .getuser ()
528+ GREEN = "\033 [92m"
529+ RED = "\033 [91m"
530+ RESET = "\033 [0m"
531+
532+ print (f"\n { GREEN } Your chainlit username is `{ username } `{ RESET } \n " )
533+
534+ if check_docker ():
535+ password = generate_password ()
536+ launch_postgres (username , password , f"{ os .environ ['CHAINLIT_APP_ROOT' ]} /pgdata" )
537+
538+ conn_string = f"postgresql+asyncpg://{ username } :{ password } @localhost:{ os .getenv ('AGENTTIDE_PG_PORT' , 5437 )} /agenttidedb"
539+ os .environ ["AGENTTIDE_PG_CONN_STR" ] = conn_string
540+ asyncio .run (init_db (os .environ ["AGENTTIDE_PG_CONN_STR" ]))
518541
519- asyncio .run (init_db (f"{ os .environ ['CHAINLIT_APP_ROOT' ]} /database.db" ))
542+ print (f"{ GREEN } PostgreSQL launched on port { os .getenv ('AGENTTIDE_PG_PORT' , 5437 )} { RESET } " )
543+ print (f"{ GREEN } Connection string stored in env var: AGENTTIDE_PG_CONN_STR{ RESET } \n " )
544+ else :
545+ print (f"{ RED } Could not find Docker on this system.{ RESET } " )
546+ print (" PostgreSQL could not be launched for persistent data storage." )
547+ print (" You won't have access to multiple conversations or history beyond each session." )
548+ print (" Consider installing Docker and ensuring it is running.\n " )
520549
521550 serve (
522551 host = args .host ,
0 commit comments