#ifndef LLSH_CONFIG_H #define LLSH_CONFIG_H #include "dotagents.h" #include "util.h" /* Mirrors config.rs: CLI + file config + merged Config. */ typedef enum { PROV_OPENAI, PROV_ANTHROPIC, PROV_OLLAMA, } provider_kind; #define LLSH_VERSION "0.1.0" typedef struct { char *prompt; char *model; char *provider; char *base_url; char *api_key; char *cwd; char *preamble; unsigned long max_turns; bool has_max_turns; unsigned long max_retries; bool has_max_retries; unsigned long context_limit; bool has_context_limit; double compact_threshold; bool has_compact_threshold; double clear_threshold; bool has_clear_threshold; bool verbose; bool allow_mcp; bool confirm_destructive; bool has_confirm_destructive; strlist shell_allowlist; strlist shell_denylist; bool debug; bool no_rubric; /* --no-rubric-compaction */ unsigned long rubric_max_summaries; bool has_rubric_max_summaries; unsigned long skill_index_cap; bool has_skill_index_cap; unsigned long shell_timeout_secs; bool has_shell_timeout_secs; unsigned long max_output_chars; bool has_max_output_chars; unsigned long max_file_bytes; bool has_max_file_bytes; char *resume; } cli; typedef struct { provider_kind provider; char *model; char *base_url; /* may be NULL */ char *api_key; /* may be NULL */ char *preamble; unsigned long max_turns; unsigned long max_retries; unsigned long context_limit; double compact_threshold; double clear_threshold; bool rubric_enabled; unsigned long rubric_max_summaries; /* 0 = unlimited */ bool verbose; unsigned long skill_index_cap; unsigned long shell_timeout_secs; unsigned long max_output_chars; unsigned long max_file_bytes; strlist shell_allowlist; strlist shell_denylist; bool confirm_destructive; } config; /* Parse argv (without program name). 0 on success; -2 prints help and returns * CLI_HELP (call should exit); -1 error. */ #define CLI_HELP (-2) int cli_parse(int argc, char **argv, cli *out, char **err); void cli_free(cli *c); /* Merge CLI + file with precedence CLI > file > defaults. Changes CWD. */ /* Build the merged config directly from CLI arguments (the former * config-file layer was removed; connection presets live in * `.agents/models.json`). */ int config_from_cli(const cli *cli, config *out, char **err); int config_merge(const cli *cli, config *out, char **err); void config_free(config *c); /* Reject key-requiring providers with neither api_key nor base_url. Run * after a models.json preset may have supplied them (the merge itself no * longer checks). */ int config_require_key_or_base(const config *c, char **err); provider_kind provider_parse(const char *raw, char **err); const char *provider_name(provider_kind k); const char *provider_default_model(provider_kind k); /* Apply a models.json `default` preset (see dotagents). Returns preset name * (caller frees) or NULL + *err. */ char *config_apply_models_preset(config *cfg, const models_file *models, const cli *cli, char **err); #endif