feat: add non-streaming LLM API, tool registry, and web_search tool
Replace SSE streaming with non-streaming JSON for Anthropic API. Add llm_chat_tools() returning structured llm_response_t with text and tool_use blocks. Implement tool registry with dispatch-by-name and web_search tool via Brave Search API (direct + proxy support). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
92
main/tools/tool_registry.c
Normal file
92
main/tools/tool_registry.c
Normal file
@@ -0,0 +1,92 @@
|
||||
#include "tool_registry.h"
|
||||
#include "tools/tool_web_search.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
static const char *TAG = "tools";
|
||||
|
||||
#define MAX_TOOLS 8
|
||||
|
||||
static mimi_tool_t s_tools[MAX_TOOLS];
|
||||
static int s_tool_count = 0;
|
||||
static char *s_tools_json = NULL; /* cached JSON array string */
|
||||
|
||||
static void register_tool(const mimi_tool_t *tool)
|
||||
{
|
||||
if (s_tool_count >= MAX_TOOLS) {
|
||||
ESP_LOGE(TAG, "Tool registry full");
|
||||
return;
|
||||
}
|
||||
s_tools[s_tool_count++] = *tool;
|
||||
ESP_LOGI(TAG, "Registered tool: %s", tool->name);
|
||||
}
|
||||
|
||||
static void build_tools_json(void)
|
||||
{
|
||||
cJSON *arr = cJSON_CreateArray();
|
||||
|
||||
for (int i = 0; i < s_tool_count; i++) {
|
||||
cJSON *tool = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(tool, "name", s_tools[i].name);
|
||||
cJSON_AddStringToObject(tool, "description", s_tools[i].description);
|
||||
|
||||
cJSON *schema = cJSON_Parse(s_tools[i].input_schema_json);
|
||||
if (schema) {
|
||||
cJSON_AddItemToObject(tool, "input_schema", schema);
|
||||
}
|
||||
|
||||
cJSON_AddItemToArray(arr, tool);
|
||||
}
|
||||
|
||||
free(s_tools_json);
|
||||
s_tools_json = cJSON_PrintUnformatted(arr);
|
||||
cJSON_Delete(arr);
|
||||
|
||||
ESP_LOGI(TAG, "Tools JSON built (%d tools)", s_tool_count);
|
||||
}
|
||||
|
||||
esp_err_t tool_registry_init(void)
|
||||
{
|
||||
s_tool_count = 0;
|
||||
|
||||
/* Register web_search */
|
||||
tool_web_search_init();
|
||||
|
||||
mimi_tool_t ws = {
|
||||
.name = "web_search",
|
||||
.description = "Search the web for current information. Use this when you need up-to-date facts, news, weather, or anything beyond your training data.",
|
||||
.input_schema_json =
|
||||
"{\"type\":\"object\","
|
||||
"\"properties\":{\"query\":{\"type\":\"string\",\"description\":\"The search query\"}},"
|
||||
"\"required\":[\"query\"]}",
|
||||
.execute = tool_web_search_execute,
|
||||
};
|
||||
register_tool(&ws);
|
||||
|
||||
build_tools_json();
|
||||
|
||||
ESP_LOGI(TAG, "Tool registry initialized");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
const char *tool_registry_get_tools_json(void)
|
||||
{
|
||||
return s_tools_json;
|
||||
}
|
||||
|
||||
esp_err_t tool_registry_execute(const char *name, const char *input_json,
|
||||
char *output, size_t output_size)
|
||||
{
|
||||
for (int i = 0; i < s_tool_count; i++) {
|
||||
if (strcmp(s_tools[i].name, name) == 0) {
|
||||
ESP_LOGI(TAG, "Executing tool: %s", name);
|
||||
return s_tools[i].execute(input_json, output, output_size);
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGW(TAG, "Unknown tool: %s", name);
|
||||
snprintf(output, output_size, "Error: unknown tool '%s'", name);
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
Reference in New Issue
Block a user