#include "cst_agent.h" #include #include #include #define MODEL_MAX_LEN 128 static const cst_provider_t PROVIDERS[] = { {"minimax", "https://api.minimax.cn/v1", "MiniMax-M2.7", "MINIMAX_API_KEY"}, {"deepseek", "https://api.deepseek.com/v1", "deepseek-flash", "DEEPSEEK_API_KEY"}, {"openai", "https://api.openai.com/v1", "gpt-4.1-mini", "OPENAI_API_KEY"}, }; const cst_provider_t *cst_provider_find(const char *name) { if (!name || !name[0]) return NULL; for (size_t i = 0; i < sizeof(PROVIDERS) / sizeof(PROVIDERS[0]); i++) { if (strcmp(PROVIDERS[i].name, name) == 0) return &PROVIDERS[i]; } return NULL; } const cst_provider_t *cst_provider_default(void) { const cst_provider_t *p = cst_provider_find(getenv("CST_PROVIDER")); return p ? p : &PROVIDERS[0]; } static int already(char out[][MODEL_MAX_LEN], int n, const char *name) { for (int i = 0; i < n; i++) { if (strcmp(out[i], name) == 0) return 1; } return 0; } static int push(char out[][MODEL_MAX_LEN], int *n, int max, const char *name) { if (!name || !name[0] || *n >= max) return 0; if (already(out, *n, name)) return 0; snprintf(out[*n], MODEL_MAX_LEN, "%s", name); (*n)++; return 1; } int cst_models_list(const char *current, char out[][128], int max_out) { if (!out || max_out <= 0) return 0; int n = 0; const char *env = getenv("CST_MODELS"); if (env && env[0]) { char buf[1024]; snprintf(buf, sizeof(buf), "%s", env); char *p = buf; while (*p && n < max_out) { while (*p == ':' || *p == ' ' || *p == ',') p++; if (!*p) break; char *start = p; while (*p && *p != ':' && *p != ',') p++; char save = *p; *p = 0; char *end = start + strlen(start); while (end > start && (end[-1] == ' ' || end[-1] == '\t')) *--end = 0; push(out, &n, max_out, start); *p = save; if (*p) p++; } } else { push(out, &n, max_out, "deepseek-flash"); push(out, &n, max_out, "deepseek-v4-pro"); push(out, &n, max_out, "MiniMax-M2.7"); push(out, &n, max_out, "MiniMax-M2.5"); push(out, &n, max_out, "gpt-4.1-mini"); push(out, &n, max_out, "gpt-4o"); } if (current && current[0]) push(out, &n, max_out, current); return n; } /* Context window in tokens (CST_CTX_TOKENS overrides). Prefix match. */ long cst_model_context_tokens(const char *model) { const char *e = getenv("CST_CTX_TOKENS"); if (e && atol(e) > 0) return atol(e); static const struct { const char *prefix; long tokens; } T[] = {{"deepseek", 128000}, {"MiniMax", 196608}, {"minimax", 196608}, {"gpt-4.1", 1047576}, {"gpt-4o", 128000}, {"gpt-5", 400000}, {"o3", 200000}, {"o4", 200000}, {"claude", 200000}, {"qwen", 131072}, {"glm", 128000}, {"kimi", 131072}}; if (model) { for (size_t i = 0; i < sizeof(T) / sizeof(T[0]); i++) { if (strncmp(model, T[i].prefix, strlen(T[i].prefix)) == 0) return T[i].tokens; } } return 128000; } int cst_effort_valid(const char *effort) { static const char *const ok[] = {"low", "medium", "high", "max"}; for (size_t i = 0; effort && i < sizeof(ok) / sizeof(ok[0]); i++) { if (strcmp(effort, ok[i]) == 0) return 1; } return 0; } const char *cst_effort_wire(const char *provider, const char *model, const char *effort) { if (!cst_effort_valid(effort) || !provider || !model) return NULL; if (strcmp(provider, "deepseek") == 0) return effort; /* OpenAI reasoning models take low | medium | high. */ if (strcmp(provider, "openai") == 0 && (strncmp(model, "o1", 2) == 0 || strncmp(model, "o3", 2) == 0 || strncmp(model, "o4", 2) == 0 || strncmp(model, "gpt-5", 5) == 0)) return strcmp(effort, "max") == 0 ? "high" : effort; return NULL; } int cst_provider_count(void) { return (int)(sizeof(PROVIDERS) / sizeof(PROVIDERS[0])); } const cst_provider_t *cst_provider_at(int i) { return i >= 0 && i < cst_provider_count() ? &PROVIDERS[i] : NULL; }