chore: avoid hardcoding file paths via MIMI_SPIFFS_BASE
Use MIMI_SPIFFS_BASE to centralize file path definitions, making the base path configurable instead of hardcoded. Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
@@ -40,10 +40,10 @@ esp_err_t context_build_system_prompt(char *buf, size_t size)
|
||||
"Use this when you need up-to-date facts, news, weather, or anything beyond your training data.\n"
|
||||
"- get_current_time: Get the current date and time. "
|
||||
"You do NOT have an internal clock — always use this tool when you need to know the time or date.\n"
|
||||
"- read_file: Read a file from SPIFFS (path must start with /spiffs/).\n"
|
||||
"- write_file: Write/overwrite a file on SPIFFS.\n"
|
||||
"- edit_file: Find-and-replace edit a file on SPIFFS.\n"
|
||||
"- list_dir: List files on SPIFFS, optionally filter by prefix.\n"
|
||||
"- read_file: Read a file (path must start with " MIMI_SPIFFS_BASE "/).\n"
|
||||
"- write_file: Write/overwrite a file.\n"
|
||||
"- edit_file: Find-and-replace edit a file.\n"
|
||||
"- list_dir: List files, optionally filter by prefix.\n"
|
||||
"- cron_add: Schedule a recurring or one-shot task. The message will trigger an agent turn when the job fires.\n"
|
||||
"- cron_list: List all scheduled cron jobs.\n"
|
||||
"- cron_remove: Remove a scheduled cron job by ID.\n\n"
|
||||
@@ -51,8 +51,8 @@ esp_err_t context_build_system_prompt(char *buf, size_t size)
|
||||
"Use tools when needed. Provide your final answer as text after using tools.\n\n"
|
||||
"## Memory\n"
|
||||
"You have persistent memory stored on local flash:\n"
|
||||
"- Long-term memory: /spiffs/memory/MEMORY.md\n"
|
||||
"- Daily notes: /spiffs/memory/daily/<YYYY-MM-DD>.md\n\n"
|
||||
"- Long-term memory: " MIMI_SPIFFS_MEMORY_DIR "/MEMORY.md\n"
|
||||
"- Daily notes: " MIMI_SPIFFS_MEMORY_DIR "/daily/<YYYY-MM-DD>.md\n\n"
|
||||
"IMPORTANT: Actively use memory to remember things across conversations.\n"
|
||||
"- When you learn something new about the user (name, preferences, habits, context), write it to MEMORY.md.\n"
|
||||
"- When something noteworthy happens in a conversation, append it to today's daily note.\n"
|
||||
@@ -61,9 +61,9 @@ esp_err_t context_build_system_prompt(char *buf, size_t size)
|
||||
"- Keep MEMORY.md concise and organized — summarize, don't dump raw conversation.\n"
|
||||
"- You should proactively save memory without being asked. If the user tells you their name, preferences, or important facts, persist them immediately.\n\n"
|
||||
"## Skills\n"
|
||||
"Skills are specialized instruction files stored in /spiffs/skills/.\n"
|
||||
"Skills are specialized instruction files stored in " MIMI_SKILLS_PREFIX ".\n"
|
||||
"When a task matches a skill, read the full skill file for detailed instructions.\n"
|
||||
"You can create new skills using write_file to /spiffs/skills/<name>.md.\n");
|
||||
"You can create new skills using write_file to " MIMI_SKILLS_PREFIX "<name>.md.\n");
|
||||
|
||||
/* Bootstrap files */
|
||||
off = append_file(buf, size, off, MIMI_SOUL_FILE, "Personality");
|
||||
|
||||
@@ -280,7 +280,7 @@ static int cmd_skill_list(int argc, char **argv)
|
||||
|
||||
size_t n = skill_loader_build_summary(buf, 4096);
|
||||
if (n == 0) {
|
||||
printf("No skills found under /spiffs/skills/.\n");
|
||||
printf("No skills found under " MIMI_SKILLS_PREFIX ".\n");
|
||||
} else {
|
||||
printf("=== Skills ===\n%s", buf);
|
||||
}
|
||||
@@ -307,9 +307,9 @@ static bool build_skill_path(const char *name, char *out, size_t out_size)
|
||||
if (strchr(name, '/') != NULL || strchr(name, '\\') != NULL) return false;
|
||||
|
||||
if (has_md_suffix(name)) {
|
||||
snprintf(out, out_size, "/spiffs/skills/%s", name);
|
||||
snprintf(out, out_size, MIMI_SKILLS_PREFIX "%s", name);
|
||||
} else {
|
||||
snprintf(out, out_size, "/spiffs/skills/%s.md", name);
|
||||
snprintf(out, out_size, MIMI_SKILLS_PREFIX "%s.md", name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -375,9 +375,9 @@ static int cmd_skill_search(int argc, char **argv)
|
||||
}
|
||||
|
||||
const char *keyword = skill_search_args.keyword->sval[0];
|
||||
DIR *dir = opendir("/spiffs");
|
||||
DIR *dir = opendir(MIMI_SPIFFS_BASE);
|
||||
if (!dir) {
|
||||
printf("Cannot open /spiffs.\n");
|
||||
printf("Cannot open " MIMI_SPIFFS_BASE ".\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -395,7 +395,7 @@ static int cmd_skill_search(int argc, char **argv)
|
||||
if (strcmp(name + name_len - 3, ".md") != 0) continue;
|
||||
|
||||
char full_path[296];
|
||||
snprintf(full_path, sizeof(full_path), "/spiffs/%s", name);
|
||||
snprintf(full_path, sizeof(full_path), MIMI_SPIFFS_BASE "/%s", name);
|
||||
|
||||
bool file_matched = contains_nocase(name, keyword);
|
||||
int matched_line = 0;
|
||||
@@ -655,7 +655,7 @@ esp_err_t serial_cli_init(void)
|
||||
/* skill_list */
|
||||
esp_console_cmd_t skill_list_cmd = {
|
||||
.command = "skill_list",
|
||||
.help = "List installed skills from /spiffs/skills/",
|
||||
.help = "List installed skills from " MIMI_SKILLS_PREFIX,
|
||||
.func = &cmd_skill_list,
|
||||
};
|
||||
esp_console_cmd_register(&skill_list_cmd);
|
||||
|
||||
@@ -83,24 +83,24 @@
|
||||
|
||||
/* Memory / SPIFFS */
|
||||
#define MIMI_SPIFFS_BASE "/spiffs"
|
||||
#define MIMI_SPIFFS_CONFIG_DIR "/spiffs/config"
|
||||
#define MIMI_SPIFFS_MEMORY_DIR "/spiffs/memory"
|
||||
#define MIMI_SPIFFS_SESSION_DIR "/spiffs/sessions"
|
||||
#define MIMI_MEMORY_FILE "/spiffs/memory/MEMORY.md"
|
||||
#define MIMI_SOUL_FILE "/spiffs/config/SOUL.md"
|
||||
#define MIMI_USER_FILE "/spiffs/config/USER.md"
|
||||
#define MIMI_SPIFFS_CONFIG_DIR MIMI_SPIFFS_BASE "/config"
|
||||
#define MIMI_SPIFFS_MEMORY_DIR MIMI_SPIFFS_BASE "/memory"
|
||||
#define MIMI_SPIFFS_SESSION_DIR MIMI_SPIFFS_BASE "/sessions"
|
||||
#define MIMI_MEMORY_FILE MIMI_SPIFFS_MEMORY_DIR "/MEMORY.md"
|
||||
#define MIMI_SOUL_FILE MIMI_SPIFFS_CONFIG_DIR "/SOUL.md"
|
||||
#define MIMI_USER_FILE MIMI_SPIFFS_CONFIG_DIR "/USER.md"
|
||||
#define MIMI_CONTEXT_BUF_SIZE (16 * 1024)
|
||||
#define MIMI_SESSION_MAX_MSGS 20
|
||||
|
||||
/* Cron / Heartbeat */
|
||||
#define MIMI_CRON_FILE "/spiffs/cron.json"
|
||||
#define MIMI_CRON_FILE MIMI_SPIFFS_BASE "/cron.json"
|
||||
#define MIMI_CRON_MAX_JOBS 16
|
||||
#define MIMI_CRON_CHECK_INTERVAL_MS (60 * 1000)
|
||||
#define MIMI_HEARTBEAT_FILE "/spiffs/HEARTBEAT.md"
|
||||
#define MIMI_HEARTBEAT_FILE MIMI_SPIFFS_BASE "/HEARTBEAT.md"
|
||||
#define MIMI_HEARTBEAT_INTERVAL_MS (30 * 60 * 1000)
|
||||
|
||||
/* Skills */
|
||||
#define MIMI_SKILLS_PREFIX "/spiffs/skills/"
|
||||
#define MIMI_SKILLS_PREFIX MIMI_SPIFFS_BASE "/skills/"
|
||||
|
||||
/* WebSocket Gateway */
|
||||
#define MIMI_WS_PORT 18789
|
||||
|
||||
@@ -41,7 +41,7 @@ static const char *TAG = "skills";
|
||||
"\n" \
|
||||
"## How to use\n" \
|
||||
"1. Use get_current_time for today's date\n" \
|
||||
"2. Read /spiffs/memory/MEMORY.md for user preferences and context\n" \
|
||||
"2. Read " MIMI_SPIFFS_MEMORY_DIR "/MEMORY.md for user preferences and context\n" \
|
||||
"3. Read today's daily note if it exists\n" \
|
||||
"4. Use web_search for relevant news based on user interests\n" \
|
||||
"5. Compile a concise briefing covering:\n" \
|
||||
@@ -70,7 +70,7 @@ static const char *TAG = "skills";
|
||||
" - `## When to use` — trigger conditions\n" \
|
||||
" - `## How to use` — step-by-step instructions\n" \
|
||||
" - `## Example` — concrete example (optional but helpful)\n" \
|
||||
"3. Save to `/spiffs/skills/<name>.md` using write_file\n" \
|
||||
"3. Save to `" MIMI_SKILLS_PREFIX "<name>.md` using write_file\n" \
|
||||
"4. The skill will be automatically available after the next conversation\n" \
|
||||
"\n" \
|
||||
"## Best practices\n" \
|
||||
@@ -81,7 +81,7 @@ static const char *TAG = "skills";
|
||||
"\n" \
|
||||
"## Example\n" \
|
||||
"To create a \"translate\" skill:\n" \
|
||||
"write_file path=\"/spiffs/skills/translate.md\" content=\"# Translate\\n\\nTranslate text between languages.\\n\\n" \
|
||||
"write_file path=\"" MIMI_SKILLS_PREFIX "translate.md\" content=\"# Translate\\n\\nTranslate text between languages.\\n\\n" \
|
||||
"## When to use\\nWhen the user asks to translate text.\\n\\n" \
|
||||
"## How to use\\n1. Identify source and target languages\\n" \
|
||||
"2. Translate directly using your language knowledge\\n" \
|
||||
|
||||
@@ -15,12 +15,17 @@ static const char *TAG = "tool_files";
|
||||
#define MAX_FILE_SIZE (32 * 1024)
|
||||
|
||||
/**
|
||||
* Validate that a path starts with /spiffs/ and contains no ".." traversal.
|
||||
* Validate that a path starts with MIMI_SPIFFS_BASE and contains no ".." traversal.
|
||||
*/
|
||||
static bool validate_path(const char *path)
|
||||
{
|
||||
if (!path) return false;
|
||||
if (strncmp(path, "/spiffs/", 8) != 0) return false;
|
||||
size_t base_len = strlen(MIMI_SPIFFS_BASE);
|
||||
if (strncmp(path, MIMI_SPIFFS_BASE, base_len) != 0) return false;
|
||||
/* Require a path separator after the base (unless base ends with '/') */
|
||||
if (base_len > 0 && MIMI_SPIFFS_BASE[base_len - 1] != '/') {
|
||||
if (path[base_len] != '/') return false;
|
||||
}
|
||||
if (strstr(path, "..") != NULL) return false;
|
||||
return true;
|
||||
}
|
||||
@@ -37,7 +42,7 @@ esp_err_t tool_read_file_execute(const char *input_json, char *output, size_t ou
|
||||
|
||||
const char *path = cJSON_GetStringValue(cJSON_GetObjectItem(root, "path"));
|
||||
if (!validate_path(path)) {
|
||||
snprintf(output, output_size, "Error: path must start with /spiffs/ and must not contain '..'");
|
||||
snprintf(output, output_size, "Error: path must start with %s/ and must not contain '..'", MIMI_SPIFFS_BASE);
|
||||
cJSON_Delete(root);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
@@ -75,7 +80,7 @@ esp_err_t tool_write_file_execute(const char *input_json, char *output, size_t o
|
||||
const char *content = cJSON_GetStringValue(cJSON_GetObjectItem(root, "content"));
|
||||
|
||||
if (!validate_path(path)) {
|
||||
snprintf(output, output_size, "Error: path must start with /spiffs/ and must not contain '..'");
|
||||
snprintf(output, output_size, "Error: path must start with %s/ and must not contain '..'", MIMI_SPIFFS_BASE);
|
||||
cJSON_Delete(root);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
@@ -123,7 +128,7 @@ esp_err_t tool_edit_file_execute(const char *input_json, char *output, size_t ou
|
||||
const char *new_str = cJSON_GetStringValue(cJSON_GetObjectItem(root, "new_string"));
|
||||
|
||||
if (!validate_path(path)) {
|
||||
snprintf(output, output_size, "Error: path must start with /spiffs/ and must not contain '..'");
|
||||
snprintf(output, output_size, "Error: path must start with %s/ and must not contain '..'", MIMI_SPIFFS_BASE);
|
||||
cJSON_Delete(root);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
@@ -226,7 +231,7 @@ esp_err_t tool_list_dir_execute(const char *input_json, char *output, size_t out
|
||||
|
||||
DIR *dir = opendir(MIMI_SPIFFS_BASE);
|
||||
if (!dir) {
|
||||
snprintf(output, output_size, "Error: cannot open /spiffs directory");
|
||||
snprintf(output, output_size, "Error: cannot open %s directory", MIMI_SPIFFS_BASE);
|
||||
cJSON_Delete(root);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
@@ -5,24 +5,24 @@
|
||||
|
||||
/**
|
||||
* Read a file from SPIFFS.
|
||||
* Input JSON: {"path": "/spiffs/..."}
|
||||
* Input JSON: {"path": "<MIMI_SPIFFS_BASE>/..."}
|
||||
*/
|
||||
esp_err_t tool_read_file_execute(const char *input_json, char *output, size_t output_size);
|
||||
|
||||
/**
|
||||
* Write/overwrite a file on SPIFFS.
|
||||
* Input JSON: {"path": "/spiffs/...", "content": "..."}
|
||||
* Input JSON: {"path": "<MIMI_SPIFFS_BASE>/...", "content": "..."}
|
||||
*/
|
||||
esp_err_t tool_write_file_execute(const char *input_json, char *output, size_t output_size);
|
||||
|
||||
/**
|
||||
* Find-and-replace edit a file on SPIFFS.
|
||||
* Input JSON: {"path": "/spiffs/...", "old_string": "...", "new_string": "..."}
|
||||
* Input JSON: {"path": "<MIMI_SPIFFS_BASE>/...", "old_string": "...", "new_string": "..."}
|
||||
*/
|
||||
esp_err_t tool_edit_file_execute(const char *input_json, char *output, size_t output_size);
|
||||
|
||||
/**
|
||||
* List files on SPIFFS, optionally filtered by path prefix.
|
||||
* Input JSON: {"prefix": "/spiffs/..."} (prefix is optional)
|
||||
* Input JSON: {"prefix": "<MIMI_SPIFFS_BASE>/..."} (prefix is optional)
|
||||
*/
|
||||
esp_err_t tool_list_dir_execute(const char *input_json, char *output, size_t output_size);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "tool_registry.h"
|
||||
#include "mimi_config.h"
|
||||
#include "tools/tool_web_search.h"
|
||||
#include "tools/tool_get_time.h"
|
||||
#include "tools/tool_files.h"
|
||||
@@ -83,10 +84,10 @@ esp_err_t tool_registry_init(void)
|
||||
/* Register read_file */
|
||||
mimi_tool_t rf = {
|
||||
.name = "read_file",
|
||||
.description = "Read a file from SPIFFS storage. Path must start with /spiffs/.",
|
||||
.description = "Read a file from SPIFFS storage. Path must start with " MIMI_SPIFFS_BASE "/.",
|
||||
.input_schema_json =
|
||||
"{\"type\":\"object\","
|
||||
"\"properties\":{\"path\":{\"type\":\"string\",\"description\":\"Absolute path starting with /spiffs/\"}},"
|
||||
"\"properties\":{\"path\":{\"type\":\"string\",\"description\":\"Absolute path starting with " MIMI_SPIFFS_BASE "/\"}},"
|
||||
"\"required\":[\"path\"]}",
|
||||
.execute = tool_read_file_execute,
|
||||
};
|
||||
@@ -95,10 +96,10 @@ esp_err_t tool_registry_init(void)
|
||||
/* Register write_file */
|
||||
mimi_tool_t wf = {
|
||||
.name = "write_file",
|
||||
.description = "Write or overwrite a file on SPIFFS storage. Path must start with /spiffs/.",
|
||||
.description = "Write or overwrite a file on SPIFFS storage. Path must start with " MIMI_SPIFFS_BASE "/.",
|
||||
.input_schema_json =
|
||||
"{\"type\":\"object\","
|
||||
"\"properties\":{\"path\":{\"type\":\"string\",\"description\":\"Absolute path starting with /spiffs/\"},"
|
||||
"\"properties\":{\"path\":{\"type\":\"string\",\"description\":\"Absolute path starting with " MIMI_SPIFFS_BASE "/\"},"
|
||||
"\"content\":{\"type\":\"string\",\"description\":\"File content to write\"}},"
|
||||
"\"required\":[\"path\",\"content\"]}",
|
||||
.execute = tool_write_file_execute,
|
||||
@@ -111,7 +112,7 @@ esp_err_t tool_registry_init(void)
|
||||
.description = "Find and replace text in a file on SPIFFS. Replaces first occurrence of old_string with new_string.",
|
||||
.input_schema_json =
|
||||
"{\"type\":\"object\","
|
||||
"\"properties\":{\"path\":{\"type\":\"string\",\"description\":\"Absolute path starting with /spiffs/\"},"
|
||||
"\"properties\":{\"path\":{\"type\":\"string\",\"description\":\"Absolute path starting with " MIMI_SPIFFS_BASE "/\"},"
|
||||
"\"old_string\":{\"type\":\"string\",\"description\":\"Text to find\"},"
|
||||
"\"new_string\":{\"type\":\"string\",\"description\":\"Replacement text\"}},"
|
||||
"\"required\":[\"path\",\"old_string\",\"new_string\"]}",
|
||||
@@ -125,7 +126,7 @@ esp_err_t tool_registry_init(void)
|
||||
.description = "List files on SPIFFS storage, optionally filtered by path prefix.",
|
||||
.input_schema_json =
|
||||
"{\"type\":\"object\","
|
||||
"\"properties\":{\"prefix\":{\"type\":\"string\",\"description\":\"Optional path prefix filter, e.g. /spiffs/memory/\"}},"
|
||||
"\"properties\":{\"prefix\":{\"type\":\"string\",\"description\":\"Optional path prefix filter, e.g. " MIMI_SPIFFS_BASE "/memory/\"}},"
|
||||
"\"required\":[]}",
|
||||
.execute = tool_list_dir_execute,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user