1+ import os
12import pathlib
23import shutil
34import time
2021 format_runs ,
2122 format_strike_models ,
2223 format_strikes ,
23- format_user_models ,
2424)
2525from dreadnode_cli .agent .templates import cli as templates_cli
2626from dreadnode_cli .agent .templates .format import format_templates
2727from dreadnode_cli .agent .templates .manager import TemplateManager
28- from dreadnode_cli .config import UserConfig , UserModel , UserModels
28+ from dreadnode_cli .api import Client
29+ from dreadnode_cli .config import UserConfig
30+ from dreadnode_cli .model .config import UserModels
31+ from dreadnode_cli .model .format import format_user_models
2932from dreadnode_cli .profile .cli import switch as switch_profile
3033from dreadnode_cli .types import GithubRepo
3134from dreadnode_cli .utils import download_and_unzip_archive , get_repo_archive_source_path , pretty_cli
3235
3336cli = typer .Typer (no_args_is_help = True )
3437
35- cli .add_typer (templates_cli , name = "templates" , help = "Interact with Strike templates" )
38+ cli .add_typer (templates_cli , name = "templates" , help = "Manage Agent templates" )
3639
3740
3841def ensure_profile (agent_config : AgentConfig , * , user_config : UserConfig | None = None ) -> None :
@@ -48,8 +51,8 @@ def ensure_profile(agent_config: AgentConfig, *, user_config: UserConfig | None
4851 plural = "s" if len (agent_config .linked_profiles ) > 1 else ""
4952 raise Exception (
5053 f"This agent is linked to the [magenta]{ linked_profiles } [/] server profile{ plural } , "
51- f"but the current server profile is [yellow]{ user_config .active_profile_name } [/], " ,
52- "use [bold]dreadnode agent push[/] to create a new link with this profile." ,
54+ f"but the current server profile is [yellow]{ user_config .active_profile_name } [/], "
55+ "use [bold]dreadnode agent push[/] to create a new link with this profile."
5356 )
5457
5558 if agent_config .active_link .profile != user_config .active_profile_name :
@@ -70,7 +73,7 @@ def ensure_profile(agent_config: AgentConfig, *, user_config: UserConfig | None
7073 switch_profile (agent_config .active_link .profile )
7174
7275
73- @cli .command (help = "Initialize a new agent project" )
76+ @cli .command (help = "Initialize a new agent project" , no_args_is_help = True )
7477@pretty_cli
7578def init (
7679 strike : t .Annotated [str , typer .Argument (help = "The target strike" )],
@@ -341,19 +344,34 @@ def deploy(
341344 raise Exception ("No strike specified, use -s/--strike or set the strike in the agent config" )
342345
343346 user_models = UserModels .read ()
344- user_model : UserModel | None = None
345-
346- # Verify the model if it was supplied
347- if model is not None :
348- # check if it's a user model
349- user_model = next ((m for m in user_models .models if m .key == model ), None )
350- if not user_model :
351- # check if it's a strike model
352- strike_response = client .get_strike (strike )
353- if not any (m .key == model for m in strike_response .models ):
354- models (directory , strike = strike )
355- print ()
356- raise Exception (f"Model '{ model } ' is not a user model nor was found in strike '{ strike_response .name } '" )
347+ user_model : Client .UserModel | None = None
348+
349+ # Check for a user-defined model
350+ if model in user_models .models :
351+ user_model = Client .UserModel (
352+ key = model ,
353+ generator_id = user_models .models [model ].generator_id ,
354+ api_key = user_models .models [model ].api_key ,
355+ )
356+
357+ # Resolve the API key from env vars
358+ if user_model .api_key .startswith ("$" ):
359+ try :
360+ user_model .api_key = os .environ [user_model .api_key [1 :]]
361+ except KeyError as e :
362+ raise Exception (
363+ f"API key cannot be read from '{ user_model .api_key } ', environment variable not found."
364+ ) from e
365+
366+ # Otherwise we'll ensure this is a valid strike-native model
367+ if user_model is None and model is not None :
368+ strike_response = client .get_strike (strike )
369+ if not any (m .key == model for m in strike_response .models ):
370+ models (directory , strike = strike )
371+ print ()
372+ raise Exception (
373+ f"Model '{ model } ' is not user-defined nor is it available in strike '{ strike_response .name } '"
374+ )
357375
358376 run = client .start_strike_run (agent .latest_version .id , strike = strike , model = model , user_model = user_model )
359377 agent_config .add_run (run .id ).write (directory )
@@ -380,20 +398,21 @@ def models(
380398) -> None :
381399 user_models = UserModels .read ()
382400 if user_models .models :
383- print ("[bold]User models:[/]\n " )
401+ print ("[bold]User-defined models:[/]\n " )
384402 print (format_user_models (user_models .models ))
403+ print ()
385404
386405 if strike is None :
387406 agent_config = AgentConfig .read (directory )
388407 ensure_profile (agent_config )
408+ strike = agent_config .strike
389409
390- strike = strike or agent_config .strike
391410 if strike is None :
392411 raise Exception ("No strike specified, use -s/--strike or set the strike in the agent config" )
393412
394413 strike_response = api .create_client ().get_strike (strike )
395414 if user_models .models :
396- print ("\n [bold]Strike models:[/]\n " )
415+ print ("\n [bold]Dreadnode-provided models:[/]\n " )
397416 print (format_strike_models (strike_response .models ))
398417
399418
@@ -522,7 +541,7 @@ def links(
522541 print (table )
523542
524543
525- @cli .command (help = "Switch to a different agent link" )
544+ @cli .command (help = "Switch to a different agent link" , no_args_is_help = True )
526545@pretty_cli
527546def switch (
528547 agent_or_profile : t .Annotated [str , typer .Argument (help = "Agent key/id or profile name" )],
@@ -544,7 +563,7 @@ def switch(
544563 print (f":exclamation: '{ agent_or_profile } ' not found, use [bold]dreadnode agent links[/]" )
545564
546565
547- @cli .command (help = "Clone a github repository" )
566+ @cli .command (help = "Clone a github repository" , no_args_is_help = True )
548567@pretty_cli
549568def clone (
550569 repo : t .Annotated [str , typer .Argument (help = "Repository name or URL" )],
0 commit comments