11from typing import Optional
2- import os , sys
2+ import os
3+ import sys
34import time
45from datetime import datetime
5- from pathlib import Path
66
77import json
88import shutil
2626from agentstack import inputs
2727from agentstack .agents import get_all_agents
2828from agentstack .tasks import get_all_tasks
29- from agentstack .utils import open_json_file , term_color , is_snake_case , get_framework
29+ from agentstack .utils import open_json_file , term_color , is_snake_case , get_framework , validator_not_empty
3030from agentstack .proj_templates import TemplateConfig
31+ from agentstack .exceptions import ValidationError
3132
3233
3334PREFERRED_MODELS = [
@@ -184,6 +185,75 @@ def ask_framework() -> str:
184185 return framework
185186
186187
188+ def get_validated_input (
189+ message : str ,
190+ validate_func = None ,
191+ min_length : int = 0 ,
192+ snake_case : bool = False ,
193+ ) -> str :
194+ """Helper function to get validated input from user.
195+
196+ Args:
197+ message: The prompt message to display
198+ validate_func: Optional custom validation function
199+ min_length: Minimum length requirement (0 for no requirement)
200+ snake_case: Whether to enforce snake_case naming
201+ """
202+ while True :
203+ try :
204+ value = inquirer .text (
205+ message = message ,
206+ validate = validate_func or validator_not_empty (min_length ) if min_length else None ,
207+ )
208+ if snake_case and not is_snake_case (value ):
209+ raise ValidationError ("Input must be in snake_case" )
210+ return value
211+ except ValidationError as e :
212+ print (term_color (f"Error: { str (e )} " , 'red' ))
213+
214+
215+ def ask_agent_details ():
216+ agent = {}
217+
218+ agent ['name' ] = get_validated_input (
219+ "What's the name of this agent? (snake_case)" , min_length = 3 , snake_case = True
220+ )
221+
222+ agent ['role' ] = get_validated_input ("What role does this agent have?" , min_length = 3 )
223+
224+ agent ['goal' ] = get_validated_input ("What is the goal of the agent?" , min_length = 10 )
225+
226+ agent ['backstory' ] = get_validated_input ("Give your agent a backstory" , min_length = 10 )
227+
228+ agent ['model' ] = inquirer .list_input (
229+ message = "What LLM should this agent use?" , choices = PREFERRED_MODELS , default = PREFERRED_MODELS [0 ]
230+ )
231+
232+ return agent
233+
234+
235+ def ask_task_details (agents : list [dict ]) -> dict :
236+ task = {}
237+
238+ task ['name' ] = get_validated_input (
239+ "What's the name of this task? (snake_case)" , min_length = 3 , snake_case = True
240+ )
241+
242+ task ['description' ] = get_validated_input ("Describe the task in more detail" , min_length = 10 )
243+
244+ task ['expected_output' ] = get_validated_input (
245+ "What do you expect the result to look like? (ex: A 5 bullet point summary of the email)" ,
246+ min_length = 10 ,
247+ )
248+
249+ task ['agent' ] = inquirer .list_input (
250+ message = "Which agent should be assigned this task?" ,
251+ choices = [a ['name' ] for a in agents ],
252+ )
253+
254+ return task
255+
256+
187257def ask_design () -> dict :
188258 use_wizard = inquirer .confirm (
189259 message = "Would you like to use the CLI wizard to set up agents and tasks?" ,
@@ -208,39 +278,10 @@ def ask_design() -> dict:
208278 while make_agent :
209279 print ('---' )
210280 print (f"Agent #{ len (agents )+ 1 } " )
211-
212- agent_incomplete = True
213281 agent = None
214- while agent_incomplete :
215- agent = inquirer .prompt (
216- [
217- inquirer .Text ("name" , message = "What's the name of this agent? (snake_case)" ),
218- inquirer .Text ("role" , message = "What role does this agent have?" ),
219- inquirer .Text ("goal" , message = "What is the goal of the agent?" ),
220- inquirer .Text ("backstory" , message = "Give your agent a backstory" ),
221- # TODO: make a list - #2
222- inquirer .Text (
223- 'model' ,
224- message = "What LLM should this agent use? (any LiteLLM provider)" ,
225- default = "openai/gpt-4" ,
226- ),
227- # inquirer.List("model", message="What LLM should this agent use? (any LiteLLM provider)", choices=[
228- # 'mixtral_llm',
229- # 'mixtral_llm',
230- # ]),
231- ]
232- )
233-
234- if not agent ['name' ] or agent ['name' ] == '' :
235- print (term_color ("Error: Agent name is required - Try again" , 'red' ))
236- agent_incomplete = True
237- elif not is_snake_case (agent ['name' ]):
238- print (term_color ("Error: Agent name must be snake case - Try again" , 'red' ))
239- else :
240- agent_incomplete = False
241-
242- make_agent = inquirer .confirm (message = "Create another agent?" )
282+ agent = ask_agent_details ()
243283 agents .append (agent )
284+ make_agent = inquirer .confirm (message = "Create another agent?" )
244285
245286 print ('' )
246287 for x in range (3 ):
@@ -257,35 +298,9 @@ def ask_design() -> dict:
257298 while make_task :
258299 print ('---' )
259300 print (f"Task #{ len (tasks ) + 1 } " )
260-
261- task_incomplete = True
262- task = None
263- while task_incomplete :
264- task = inquirer .prompt (
265- [
266- inquirer .Text ("name" , message = "What's the name of this task? (snake_case)" ),
267- inquirer .Text ("description" , message = "Describe the task in more detail" ),
268- inquirer .Text (
269- "expected_output" ,
270- message = "What do you expect the result to look like? (ex: A 5 bullet point summary of the email)" ,
271- ),
272- inquirer .List (
273- "agent" ,
274- message = "Which agent should be assigned this task?" ,
275- choices = [a ['name' ] for a in agents ], # type: ignore
276- ),
277- ]
278- )
279-
280- if not task ['name' ] or task ['name' ] == '' :
281- print (term_color ("Error: Task name is required - Try again" , 'red' ))
282- elif not is_snake_case (task ['name' ]):
283- print (term_color ("Error: Task name must be snake case - Try again" , 'red' ))
284- else :
285- task_incomplete = False
286-
287- make_task = inquirer .confirm (message = "Create another task?" )
301+ task = ask_task_details (agents )
288302 tasks .append (task )
303+ make_task = inquirer .confirm (message = "Create another task?" )
289304
290305 print ('' )
291306 for x in range (3 ):
0 commit comments