Skip to content
Draft
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
399 changes: 173 additions & 226 deletions README.md

Large diffs are not rendered by default.

431 changes: 178 additions & 253 deletions README_CN.md

Large diffs are not rendered by default.

418 changes: 179 additions & 239 deletions README_JA.md

Large diffs are not rendered by default.

Binary file removed assets/banner.png
Binary file not shown.
Binary file removed assets/esp32s3-usb-port.jpg
Binary file not shown.
Binary file removed assets/mimiclaw.png
Binary file not shown.
3 changes: 2 additions & 1 deletion main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ idf_component_register(
"tools/tool_get_time.c"
"tools/tool_files.c"
"skills/skill_loader.c"
"voice/voice_channel.c"
INCLUDE_DIRS
"."
REQUIRES
nvs_flash esp_wifi esp_netif esp_http_client esp_http_server
esp_https_ota esp_event json spiffs console vfs app_update esp-tls
esp_timer esp_websocket_client
esp_timer esp_websocket_client driver
)
26 changes: 25 additions & 1 deletion main/agent/agent_loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,30 @@ static void append_turn_context_prompt(char *prompt, size_t size, const mimi_msg
if (n < 0 || (size_t)n >= (size - off)) {
prompt[size - 1] = '\0';
}

if (msg->channel[0] && strcmp(msg->channel, MIMI_CHAN_VOICE) == 0) {
off = strnlen(prompt, size - 1);
if (off >= size - 1) {
return;
}

n = snprintf(
prompt + off, size - off,
"\n## Voice Output Constraints\n"
"This reply will be converted to speech (TTS) and played on a small speaker.\n"
"- Use English, natural spoken style.\n"
"- Keep it short: keep playback within ~%d seconds.\n"
"- Structure: at most 2 sentences + 1 short follow-up question.\n"
"- Length: <= %d characters total.\n"
"- No markdown, no lists, no code blocks, no URLs.\n"
"- Avoid long explanations; if the answer is long, give a 1–2 sentence summary and ask if the user wants more.\n",
(int)MIMI_VOICE_TTS_MAX_SECONDS,
(int)MIMI_VOICE_LLM_MAX_CHARS);

if (n < 0 || (size_t)n >= (size - off)) {
prompt[size - 1] = '\0';
}
}
}

static char *patch_tool_input_with_context(const llm_tool_call_t *call, const mimi_msg_t *msg)
Expand Down Expand Up @@ -218,7 +242,7 @@ static void agent_loop_task(void *arg)
while (iteration < MIMI_AGENT_MAX_TOOL_ITER) {
/* Send "working" indicator before each API call */
#if MIMI_AGENT_SEND_WORKING_STATUS
if (!sent_working_status && strcmp(msg.channel, MIMI_CHAN_SYSTEM) != 0) {
if (!sent_working_status && strcmp(msg.channel, MIMI_CHAN_SYSTEM) != 0 && strcmp(msg.channel, MIMI_CHAN_VOICE) != 0) {
mimi_msg_t status = {0};
strncpy(status.channel, msg.channel, sizeof(status.channel) - 1);
strncpy(status.chat_id, msg.chat_id, sizeof(status.chat_id) - 1);
Expand Down
1 change: 1 addition & 0 deletions main/bus/message_bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define MIMI_CHAN_WEBSOCKET "websocket"
#define MIMI_CHAN_CLI "cli"
#define MIMI_CHAN_SYSTEM "system"
#define MIMI_CHAN_VOICE "voice"

/* Message types on the bus */
typedef struct {
Expand Down
32 changes: 31 additions & 1 deletion main/cli/serial_cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ static struct {
struct arg_end *end;
} api_key_args;

/* --- set_api_base command --- */
static struct {
struct arg_str *base;
struct arg_end *end;
} api_base_args;

static int cmd_set_api_key(int argc, char **argv)
{
int nerrors = arg_parse(argc, argv, (void **)&api_key_args);
Expand All @@ -135,6 +141,18 @@ static int cmd_set_api_key(int argc, char **argv)
return 0;
}

static int cmd_set_api_base(int argc, char **argv)
{
int nerrors = arg_parse(argc, argv, (void **)&api_base_args);
if (nerrors != 0) {
arg_print_errors(stderr, api_base_args.end, argv[0]);
return 1;
}
llm_set_api_base(api_base_args.base->sval[0]);
printf("API base set.\n");
return 0;
}

/* --- set_model command --- */
static struct {
struct arg_str *model;
Expand Down Expand Up @@ -535,6 +553,7 @@ static int cmd_config_show(int argc, char **argv)
print_config("WiFi Pass", MIMI_NVS_WIFI, MIMI_NVS_KEY_PASS, MIMI_SECRET_WIFI_PASS, true);
print_config("TG Token", MIMI_NVS_TG, MIMI_NVS_KEY_TG_TOKEN, MIMI_SECRET_TG_TOKEN, true);
print_config("API Key", MIMI_NVS_LLM, MIMI_NVS_KEY_API_KEY, MIMI_SECRET_API_KEY, true);
print_config("API Base", MIMI_NVS_LLM, MIMI_NVS_KEY_API_BASE, MIMI_SECRET_API_BASE, false);
print_config("Model", MIMI_NVS_LLM, MIMI_NVS_KEY_MODEL, MIMI_SECRET_MODEL, false);
print_config("Provider", MIMI_NVS_LLM, MIMI_NVS_KEY_PROVIDER, MIMI_SECRET_MODEL_PROVIDER, false);
print_config("Proxy Host", MIMI_NVS_PROXY, MIMI_NVS_KEY_PROXY_HOST, MIMI_SECRET_PROXY_HOST, false);
Expand Down Expand Up @@ -849,6 +868,17 @@ esp_err_t serial_cli_init(void)
};
esp_console_cmd_register(&api_key_cmd);

/* set_api_base */
api_base_args.base = arg_str1(NULL, NULL, "<base>", "LLM API base (http(s)://host[:port][/path])");
api_base_args.end = arg_end(1);
esp_console_cmd_t api_base_cmd = {
.command = "set_api_base",
.help = "Set LLM API base (e.g. https://api.anthropic.com/v1)",
.func = &cmd_set_api_base,
.argtable = &api_base_args,
};
esp_console_cmd_register(&api_base_cmd);

/* set_model */
model_args.model = arg_str1(NULL, NULL, "<model>", "Model identifier");
model_args.end = arg_end(1);
Expand Down Expand Up @@ -1054,4 +1084,4 @@ esp_err_t serial_cli_init(void)
ESP_LOGI(TAG, "Serial CLI started");

return ESP_OK;
}
}
Loading