11"""Configuration for sdk-client Lambda."""
2+ import logging
23import os
4+ import tomllib
35from dataclasses import dataclass
6+ from pathlib import Path
7+ from typing import Optional
8+
9+ logger = logging .getLogger (__name__ )
10+ DEFAULT_CONFIG_PATH = Path (__file__ ).with_name ("config.toml" )
11+
12+
13+ def extract_command (text : Optional [str ]) -> Optional [str ]:
14+ """Extract command (with leading slash) from text, ignoring arguments/bot names."""
15+ if not text :
16+ return None
17+
18+ trimmed = text .strip ()
19+ if not trimmed .startswith ('/' ):
20+ return None
21+
22+ command = trimmed .split ()[0 ]
23+ if '@' in command :
24+ command = command .split ('@' , 1 )[0 ]
25+ command = command .strip ()
26+ if not command or command == '/' :
27+ return None
28+ return command
29+
30+
31+ def _load_config (config_path : Path = DEFAULT_CONFIG_PATH ) -> tuple [list [str ], dict [str , str ]]:
32+ """Load agent/local commands from TOML config file."""
33+ if not config_path .exists ():
34+ return [], {}
35+
36+ try :
37+ with config_path .open ('rb' ) as f :
38+ data = tomllib .load (f )
39+ agent_commands = data .get ('agent_commands' , {}).get ('commands' , [])
40+ if not isinstance (agent_commands , list ):
41+ logger .warning ("Agent commands config is not a list; ignoring configuration" )
42+ agent_commands = []
43+ agent_commands = [cmd for cmd in agent_commands if isinstance (cmd , str )]
44+
45+ local_commands_raw = data .get ('local_commands' , {})
46+ if not isinstance (local_commands_raw , dict ):
47+ logger .warning ("Local commands config is not a table; ignoring configuration" )
48+ local_commands_raw = {}
49+ local_commands = {
50+ f"/{ name .lstrip ('/' )} " if not name .startswith ('/' ) else name : str (value )
51+ for name , value in local_commands_raw .items ()
52+ if isinstance (name , str ) and isinstance (value , str )
53+ }
54+
55+ return agent_commands , local_commands
56+ except (OSError , tomllib .TOMLDecodeError ) as exc : # pragma: no cover - defensive logging
57+ logger .warning ("Failed to load command configuration: %s" , exc )
58+ return [], {}
459
560
661@dataclass
@@ -11,13 +66,40 @@ class Config:
1166 agent_server_url : str
1267 auth_token : str
1368 queue_url : str
69+ agent_commands : list [str ]
70+ local_commands : dict [str , str ]
1471
1572 @classmethod
16- def from_env (cls ) -> 'Config' :
73+ def from_env (cls , config_path : Optional [ Path ] = None ) -> 'Config' :
1774 """Load configuration from environment variables."""
75+ agent_cmds , local_cmds = _load_config (config_path or DEFAULT_CONFIG_PATH )
1876 return cls (
1977 telegram_token = os .getenv ('TELEGRAM_BOT_TOKEN' , '' ),
2078 agent_server_url = os .getenv ('AGENT_SERVER_URL' , '' ),
2179 auth_token = os .getenv ('SDK_CLIENT_AUTH_TOKEN' , 'default-token' ),
2280 queue_url = os .getenv ('QUEUE_URL' , '' ),
81+ agent_commands = agent_cmds ,
82+ local_commands = local_cmds ,
2383 )
84+
85+ def get_command (self , text : Optional [str ]) -> Optional [str ]:
86+ return extract_command (text )
87+
88+ def is_agent_command (self , cmd : Optional [str ]) -> bool :
89+ return bool (cmd ) and cmd in self .agent_commands
90+
91+ def is_local_command (self , cmd : Optional [str ]) -> bool :
92+ return bool (cmd ) and cmd in self .local_commands
93+
94+ def local_response (self , cmd : str ) -> str :
95+ return self .local_commands .get (cmd , "Unsupported command." )
96+
97+ def unknown_command_message (self ) -> str :
98+ parts = []
99+ if self .agent_commands :
100+ parts .append ("Agent commands:\n " + "\n " .join (self .agent_commands ))
101+ if self .local_commands :
102+ parts .append ("Local commands:\n " + "\n " .join (self .local_commands .keys ()))
103+ if not parts :
104+ return "Unsupported command."
105+ return "Unsupported command.\n \n " + "\n \n " .join (parts )
0 commit comments