def get_config(self, args: list[str] | None = None) -> BaseSettings:
        """Get the configuration object from defaults and command arguments."""

        # >>> Step 1: Use argparse to add a --config option to load whole config files

        # The defaults if no config file is provided
        # Otherwise, the configs from the respective classes will be used
        parser = ArgumentParser(description=__doc__, add_help=False)
        parser.add_argument(
            "--config",
            type=Path,
            action="append",
            default=[],
            help=(
                "Load additional config files. Use this option multiple times to load "
                "multiple files, e.g., --config config1.yaml --config config2.yaml"
            ),
        )
        parser.add_argument(
            "-h",
            "--help",
            help="Show help text and exit",
            action="store_true",
        )
        parser.add_argument(
            "--help_option",
            help="Show help text for a specific option",
        )
        if self.default_settings:
            parser.add_argument(
                "--no_config_file",
                action="store_true",
                help="Do not load default config file when no config file is provided",
            )
        parser.add_argument(
            "--print_config",
            action="store_true",
            help="Print the final config and exit",
        )

        # >>> Step 2: Parse argparse arguments but keep all the remaining arguments.
        # Explicitly handle --help and --print-options

        cli_args, remaining_args = parser.parse_known_args(args)

        if cli_args.help:
            if self.help_text:
                rich_print(self.help_text)
            else:
                parser.print_help()
            exit(0)
        if cli_args.help_option:
            module, _, name = cli_args.help_option.rpartition(".")
            if module not in sys.modules:
                __import__(module)
            type_ = getattr(sys.modules[module], name)
            rich_print(ConfigHelper().get_help(type_))
            exit(0)

        # >>> Step 3: Load config files and merge them in a big nested data structure

        config_merged = {}
        config_files = []
        if cli_args.config:
            config_files.extend(cli_args.config)
            for _f in cli_args.config:
                txt = Path(_f).read_text()
                if not txt.strip():
                    self.logger.warning(f"Config file {_f} is empty")
                    continue
                _loaded = yaml.safe_load(txt)
                merge_nested_dicts(config_merged, _loaded)
        elif self.default_settings and not cli_args.no_config_file:
            config_file = self.default_config_file
            config_files.append(config_file)
            msg = (
                f"Loading default config from {config_file}, because no other "
                "config file is specified. Specify --no_config_file to disable this."
            )
            self.logger.info(msg)
            txt = config_file.read_text()
            if not txt.strip():
                self.logger.warning(f"Default config file {config_file} is empty")
                config_merged = {}
            else:
                config_merged = yaml.safe_load(txt)
        else:
            config_merged = {}

        # For informational purposes, we also merge in the command line options
        cl_options_dict = _parse_args_to_nested_dict(remaining_args)

        # >>> Step 4: Bring together remaining arguments and the merged config to initialize the config object
        # This is done by CliApp.run from pydantic-settings

        try:
            config: BaseSettings = CliApp.run(self.arg_type, remaining_args, **config_merged, cli_exit_on_error=False)  # type: ignore
        except ValidationError as e:
            rich_print(
                Panel.fit(
                    "[red][bold]Configuration from config files\n[/bold]"
                    "This is all the configuration that was provided from defaults, --config, and CLI arguments[/red]\n\n"
                    + yaml.dump(_shorten_strings(config_merged))
                )
            )
            rich_print(
                Panel.fit(
                    "[red][bold]Configuration from CLI arguments\n[/bold]"
                    "This is all the configuration that was provided from the command line arguments[/red]\n\n"
                    + yaml.dump(_shorten_strings(cl_options_dict))
                )
            )
            rich_print(
                Panel.fit(
                    "[red][bold]Merged configuration\n[/bold]"
                    "This is the merged configuration that was used to instantiate the config object[/red]\n\n"
                    + yaml.dump(_shorten_strings(merge_nested_dicts(config_merged, cl_options_dict)))
                )
            )
            rich_print(
                Panel.fit(
                    "[red][bold]Validation error[/bold]\n" + _VALIDATION_ERROR_HELP_TEXT + "[/red]\n" + str(e),
                )
            )
            self.maybe_show_auto_correct(remaining_args)
            msg = "Invalid configuration. Please check the above output."
            raise RuntimeError(msg) from None
        except SettingsError as e:
            rich_print(Panel.fit("[red][bold]SettingsError[/bold][/red]\n\n" + str(e) + "\n\n" + _SETTING_ERROR_HINTS))
            self.maybe_show_auto_correct(remaining_args)
            msg = "Invalid command line arguments. Please check the above output in the box."
            raise RuntimeError(msg) from None

        if cli_args.print_config:  # type: ignore
            print(yaml.dump(config.model_dump()))
            exit(0)

        # Attach config files to the arg object, because we need them for file naming purposes
        # (the output traj directory is named after the last config file)
        config._config_files = config_files  # type: ignore
        return config
Get the configuration object from defaults and command arguments.
sweagent/run/common.py