2026-02-05 18:55:38 +08:00
|
|
|
#include "context_builder.h"
|
|
|
|
|
#include "mimi_config.h"
|
|
|
|
|
#include "memory/memory_store.h"
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
#include "esp_log.h"
|
|
|
|
|
#include "cJSON.h"
|
|
|
|
|
|
|
|
|
|
static const char *TAG = "context";
|
|
|
|
|
|
|
|
|
|
static size_t append_file(char *buf, size_t size, size_t offset, const char *path, const char *header)
|
|
|
|
|
{
|
|
|
|
|
FILE *f = fopen(path, "r");
|
|
|
|
|
if (!f) return offset;
|
|
|
|
|
|
|
|
|
|
if (header && offset < size - 1) {
|
|
|
|
|
offset += snprintf(buf + offset, size - offset, "\n## %s\n\n", header);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t n = fread(buf + offset, 1, size - offset - 1, f);
|
|
|
|
|
offset += n;
|
|
|
|
|
buf[offset] = '\0';
|
|
|
|
|
fclose(f);
|
|
|
|
|
return offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
esp_err_t context_build_system_prompt(char *buf, size_t size)
|
|
|
|
|
{
|
|
|
|
|
size_t off = 0;
|
|
|
|
|
|
|
|
|
|
/* Identity header */
|
|
|
|
|
time_t now;
|
|
|
|
|
time(&now);
|
|
|
|
|
struct tm tm;
|
|
|
|
|
localtime_r(&now, &tm);
|
|
|
|
|
char time_str[64];
|
|
|
|
|
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M (%A)", &tm);
|
|
|
|
|
|
|
|
|
|
off += snprintf(buf + off, size - off,
|
|
|
|
|
"# MimiClaw\n\n"
|
|
|
|
|
"You are MimiClaw, a personal AI assistant running on an ESP32-S3 device.\n"
|
|
|
|
|
"You communicate through Telegram and WebSocket.\n\n"
|
|
|
|
|
"## Current Time\n%s\n\n"
|
2026-02-07 00:37:43 +08:00
|
|
|
"Be helpful, accurate, and concise.\n\n"
|
|
|
|
|
"## Available Tools\n"
|
|
|
|
|
"You have access to the following tools:\n"
|
|
|
|
|
"- web_search: Search the web for current information. "
|
|
|
|
|
"Use this when you need up-to-date facts, news, weather, or anything beyond your training data.\n\n"
|
|
|
|
|
"Use tools when needed. Provide your final answer as text after using tools.\n",
|
2026-02-05 18:55:38 +08:00
|
|
|
time_str);
|
|
|
|
|
|
|
|
|
|
/* Bootstrap files */
|
|
|
|
|
off = append_file(buf, size, off, MIMI_SOUL_FILE, "Personality");
|
|
|
|
|
off = append_file(buf, size, off, MIMI_USER_FILE, "User Info");
|
|
|
|
|
|
|
|
|
|
/* Long-term memory */
|
|
|
|
|
char mem_buf[4096];
|
|
|
|
|
if (memory_read_long_term(mem_buf, sizeof(mem_buf)) == ESP_OK && mem_buf[0]) {
|
|
|
|
|
off += snprintf(buf + off, size - off, "\n## Long-term Memory\n\n%s\n", mem_buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Recent daily notes (last 3 days) */
|
|
|
|
|
char recent_buf[4096];
|
|
|
|
|
if (memory_read_recent(recent_buf, sizeof(recent_buf), 3) == ESP_OK && recent_buf[0]) {
|
|
|
|
|
off += snprintf(buf + off, size - off, "\n## Recent Notes\n\n%s\n", recent_buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ESP_LOGI(TAG, "System prompt built: %d bytes", (int)off);
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
esp_err_t context_build_messages(const char *history_json, const char *user_message,
|
|
|
|
|
char *buf, size_t size)
|
|
|
|
|
{
|
|
|
|
|
/* Parse existing history */
|
|
|
|
|
cJSON *history = cJSON_Parse(history_json);
|
|
|
|
|
if (!history) {
|
|
|
|
|
history = cJSON_CreateArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Append current user message */
|
|
|
|
|
cJSON *user_msg = cJSON_CreateObject();
|
|
|
|
|
cJSON_AddStringToObject(user_msg, "role", "user");
|
|
|
|
|
cJSON_AddStringToObject(user_msg, "content", user_message);
|
|
|
|
|
cJSON_AddItemToArray(history, user_msg);
|
|
|
|
|
|
|
|
|
|
/* Serialize */
|
|
|
|
|
char *json_str = cJSON_PrintUnformatted(history);
|
|
|
|
|
cJSON_Delete(history);
|
|
|
|
|
|
|
|
|
|
if (json_str) {
|
|
|
|
|
strncpy(buf, json_str, size - 1);
|
|
|
|
|
buf[size - 1] = '\0';
|
|
|
|
|
free(json_str);
|
|
|
|
|
} else {
|
|
|
|
|
snprintf(buf, size, "[{\"role\":\"user\",\"content\":\"%s\"}]", user_message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|