Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions main/cli/serial_cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,11 @@ static int cmd_set_api_key(int argc, char **argv)
arg_print_errors(stderr, api_key_args.end, argv[0]);
return 1;
}
llm_set_api_key(api_key_args.key->sval[0]);
esp_err_t err = llm_set_api_key(api_key_args.key->sval[0]);
if (err != ESP_OK) {
printf("Error: failed to save API key (0x%x)\n", err);
return 1;
}
printf("API key saved.\n");
return 0;
}
Expand All @@ -148,7 +152,11 @@ static int cmd_set_model(int argc, char **argv)
arg_print_errors(stderr, model_args.end, argv[0]);
return 1;
}
llm_set_model(model_args.model->sval[0]);
esp_err_t err = llm_set_model(model_args.model->sval[0]);
if (err != ESP_OK) {
printf("Error: failed to save model (0x%x)\n", err);
return 1;
}
printf("Model set.\n");
return 0;
}
Expand All @@ -166,7 +174,11 @@ static int cmd_set_model_provider(int argc, char **argv)
arg_print_errors(stderr, provider_args.end, argv[0]);
return 1;
}
llm_set_provider(provider_args.provider->sval[0]);
esp_err_t err = llm_set_provider(provider_args.provider->sval[0]);
if (err != ESP_OK) {
printf("Error: invalid provider. Use: anthropic|openai|deepseek\n");
return 1;
}
printf("Model provider set.\n");
return 0;
}
Expand Down Expand Up @@ -861,7 +873,7 @@ esp_err_t serial_cli_init(void)
esp_console_cmd_register(&model_cmd);

/* set_model_provider */
provider_args.provider = arg_str1(NULL, NULL, "<provider>", "Model provider (anthropic|openai)");
provider_args.provider = arg_str1(NULL, NULL, "<provider>", "Model provider (anthropic|openai|deepseek)");
provider_args.end = arg_end(1);
esp_console_cmd_t provider_cmd = {
.command = "set_model_provider",
Expand Down
55 changes: 41 additions & 14 deletions main/llm/llm_proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,19 +182,24 @@ static esp_err_t http_event_handler(esp_http_client_event_t *evt)

/* ── Provider helpers ──────────────────────────────────────────── */

/* OpenAI-compatible: openai, deepseek (Bearer auth, /v1/chat/completions) */
static bool provider_is_openai(void)
{
return strcmp(s_provider, "openai") == 0;
return strcmp(s_provider, "openai") == 0 || strcmp(s_provider, "deepseek") == 0;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

static const char *llm_api_url(void)
{
return provider_is_openai() ? MIMI_OPENAI_API_URL : MIMI_LLM_API_URL;
if (strcmp(s_provider, "deepseek") == 0) return MIMI_DEEPSEEK_API_URL;
if (strcmp(s_provider, "openai") == 0) return MIMI_OPENAI_API_URL;
return MIMI_LLM_API_URL;
}

static const char *llm_api_host(void)
{
return provider_is_openai() ? "api.openai.com" : "api.anthropic.com";
if (strcmp(s_provider, "deepseek") == 0) return "api.deepseek.com";
if (strcmp(s_provider, "openai") == 0) return "api.openai.com";
return "api.anthropic.com";
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

static const char *llm_api_path(void)
Expand Down Expand Up @@ -233,7 +238,11 @@ esp_err_t llm_proxy_init(void)
char provider_tmp[16] = {0};
len = sizeof(provider_tmp);
if (nvs_get_str(nvs, MIMI_NVS_KEY_PROVIDER, provider_tmp, &len) == ESP_OK && provider_tmp[0]) {
safe_copy(s_provider, sizeof(s_provider), provider_tmp);
if (strcmp(provider_tmp, "anthropic") == 0 || strcmp(provider_tmp, "openai") == 0 || strcmp(provider_tmp, "deepseek") == 0) {
safe_copy(s_provider, sizeof(s_provider), provider_tmp);
} else {
ESP_LOGW(TAG, "Invalid NVS provider '%s', keeping: %s", provider_tmp, s_provider);
}
}
nvs_close(nvs);
}
Expand Down Expand Up @@ -559,7 +568,9 @@ esp_err_t llm_chat_tools(const char *system_prompt,
/* Build request body (non-streaming) */
cJSON *body = cJSON_CreateObject();
cJSON_AddStringToObject(body, "model", s_model);
if (provider_is_openai()) {
if (strcmp(s_provider, "deepseek") == 0) {
cJSON_AddNumberToObject(body, "max_tokens", MIMI_LLM_MAX_TOKENS);
} else if (strcmp(s_provider, "openai") == 0) {
cJSON_AddNumberToObject(body, "max_completion_tokens", MIMI_LLM_MAX_TOKENS);
} else {
cJSON_AddNumberToObject(body, "max_tokens", MIMI_LLM_MAX_TOKENS);
Expand Down Expand Up @@ -773,11 +784,15 @@ esp_err_t llm_chat_tools(const char *system_prompt,

esp_err_t llm_set_api_key(const char *api_key)
{
if (!api_key) return ESP_ERR_INVALID_ARG;

nvs_handle_t nvs;
ESP_ERROR_CHECK(nvs_open(MIMI_NVS_LLM, NVS_READWRITE, &nvs));
ESP_ERROR_CHECK(nvs_set_str(nvs, MIMI_NVS_KEY_API_KEY, api_key));
ESP_ERROR_CHECK(nvs_commit(nvs));
esp_err_t err = nvs_open(MIMI_NVS_LLM, NVS_READWRITE, &nvs);
if (err != ESP_OK) return err;
err = nvs_set_str(nvs, MIMI_NVS_KEY_API_KEY, api_key);
if (err == ESP_OK) err = nvs_commit(nvs);
nvs_close(nvs);
if (err != ESP_OK) return err;

safe_copy(s_api_key, sizeof(s_api_key), api_key);
ESP_LOGI(TAG, "API key saved");
Expand All @@ -786,11 +801,15 @@ esp_err_t llm_set_api_key(const char *api_key)

esp_err_t llm_set_model(const char *model)
{
if (!model) return ESP_ERR_INVALID_ARG;

nvs_handle_t nvs;
ESP_ERROR_CHECK(nvs_open(MIMI_NVS_LLM, NVS_READWRITE, &nvs));
ESP_ERROR_CHECK(nvs_set_str(nvs, MIMI_NVS_KEY_MODEL, model));
ESP_ERROR_CHECK(nvs_commit(nvs));
esp_err_t err = nvs_open(MIMI_NVS_LLM, NVS_READWRITE, &nvs);
if (err != ESP_OK) return err;
err = nvs_set_str(nvs, MIMI_NVS_KEY_MODEL, model);
if (err == ESP_OK) err = nvs_commit(nvs);
nvs_close(nvs);
if (err != ESP_OK) return err;

safe_copy(s_model, sizeof(s_model), model);
ESP_LOGI(TAG, "Model set to: %s", s_model);
Expand All @@ -799,11 +818,19 @@ esp_err_t llm_set_model(const char *model)

esp_err_t llm_set_provider(const char *provider)
{
if (!provider) return ESP_ERR_INVALID_ARG;
if (strcmp(provider, "anthropic") != 0 && strcmp(provider, "openai") != 0 && strcmp(provider, "deepseek") != 0) {
ESP_LOGE(TAG, "Invalid provider '%s'. Use: anthropic|openai|deepseek", provider);
return ESP_ERR_INVALID_ARG;
}

nvs_handle_t nvs;
ESP_ERROR_CHECK(nvs_open(MIMI_NVS_LLM, NVS_READWRITE, &nvs));
ESP_ERROR_CHECK(nvs_set_str(nvs, MIMI_NVS_KEY_PROVIDER, provider));
ESP_ERROR_CHECK(nvs_commit(nvs));
esp_err_t err = nvs_open(MIMI_NVS_LLM, NVS_READWRITE, &nvs);
if (err != ESP_OK) return err;
err = nvs_set_str(nvs, MIMI_NVS_KEY_PROVIDER, provider);
if (err == ESP_OK) err = nvs_commit(nvs);
nvs_close(nvs);
if (err != ESP_OK) return err;

safe_copy(s_provider, sizeof(s_provider), provider);
ESP_LOGI(TAG, "Provider set to: %s", s_provider);
Expand Down
2 changes: 1 addition & 1 deletion main/llm/llm_proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ esp_err_t llm_proxy_init(void);
esp_err_t llm_set_api_key(const char *api_key);

/**
* Save the LLM provider to NVS. (e.g. "anthropic", "openai")
* Save the LLM provider to NVS. (e.g. "anthropic", "openai", "deepseek")
*/
esp_err_t llm_set_provider(const char *provider);

Expand Down
3 changes: 2 additions & 1 deletion main/mimi_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,11 @@

/* LLM */
#define MIMI_LLM_DEFAULT_MODEL "claude-opus-4-5"
#define MIMI_LLM_PROVIDER_DEFAULT "anthropic"
#define MIMI_LLM_PROVIDER_DEFAULT MIMI_SECRET_MODEL_PROVIDER
#define MIMI_LLM_MAX_TOKENS 4096
#define MIMI_LLM_API_URL "https://api.anthropic.com/v1/messages"
#define MIMI_OPENAI_API_URL "https://api.openai.com/v1/chat/completions"
#define MIMI_DEEPSEEK_API_URL "https://api.deepseek.com/v1/chat/completions"
#define MIMI_LLM_API_VERSION "2023-06-01"
#define MIMI_LLM_STREAM_BUF_SIZE (32 * 1024)
#define MIMI_LLM_LOG_VERBOSE_PAYLOAD 0
Expand Down