diff --git a/main/cli/serial_cli.c b/main/cli/serial_cli.c index 32c3ce3..91e04a3 100644 --- a/main/cli/serial_cli.c +++ b/main/cli/serial_cli.c @@ -608,6 +608,78 @@ static int cmd_tool_exec(int argc, char **argv) return (err == ESP_OK) ? 0 : 1; } +/* --- web_search command --- */ +static struct { + struct arg_str *query; + struct arg_end *end; +} web_search_args; + +static bool json_escape_string(const char *in, char *out, size_t out_size) +{ + if (!in || !out || out_size == 0) return false; + size_t o = 0; + for (size_t i = 0; in[i] != '\0'; ++i) { + const char c = in[i]; + const char *esc = NULL; + switch (c) { + case '\\': esc = "\\\\"; break; + case '\"': esc = "\\\""; break; + case '\n': esc = "\\n"; break; + case '\r': esc = "\\r"; break; + case '\t': esc = "\\t"; break; + default: break; + } + if (esc) { + size_t n = strlen(esc); + if (o + n >= out_size) return false; + memcpy(&out[o], esc, n); + o += n; + continue; + } + if ((unsigned char)c < 0x20) { + continue; + } + if (o + 1 >= out_size) return false; + out[o++] = c; + } + out[o] = '\0'; + return true; +} + +static int cmd_web_search(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **)&web_search_args); + if (nerrors != 0) { + arg_print_errors(stderr, web_search_args.end, argv[0]); + return 1; + } + + char escaped_query[512]; + if (!json_escape_string(web_search_args.query->sval[0], escaped_query, sizeof(escaped_query))) { + printf("Query too long.\n"); + return 1; + } + + char input_json[640]; + int n = snprintf(input_json, sizeof(input_json), "{\"query\":\"%s\"}", escaped_query); + if (n <= 0 || n >= (int)sizeof(input_json)) { + printf("Query too long.\n"); + return 1; + } + + char *output = calloc(1, 4096); + if (!output) { + printf("Out of memory.\n"); + return 1; + } + + esp_err_t err = tool_web_search_execute(input_json, output, 4096); + printf("web_search status: %s\n", esp_err_to_name(err)); + printf("%s\n", output[0] ? output : "(empty)"); + free(output); + return (err == ESP_OK) ? 0 : 1; +} + /* --- restart command --- */ static int cmd_restart(int argc, char **argv) { @@ -896,6 +968,17 @@ esp_err_t serial_cli_init(void) }; esp_console_cmd_register(&tool_exec_cmd); + /* web_search */ + web_search_args.query = arg_str1(NULL, NULL, "", "Search query"); + web_search_args.end = arg_end(1); + esp_console_cmd_t web_search_cmd = { + .command = "web_search", + .help = "Run web search tool directly (e.g. web_search \"latest esp-idf\")", + .func = &cmd_web_search, + .argtable = &web_search_args, + }; + esp_console_cmd_register(&web_search_cmd); + /* restart */ esp_console_cmd_t restart_cmd = { .command = "restart", diff --git a/main/tools/tool_web_search.c b/main/tools/tool_web_search.c index fc0bc5f..f8bb2dc 100644 --- a/main/tools/tool_web_search.c +++ b/main/tools/tool_web_search.c @@ -190,7 +190,6 @@ static char *build_tavily_payload(const char *query) { cJSON *root = cJSON_CreateObject(); if (!root) return NULL; - cJSON_AddStringToObject(root, "api_key", s_tavily_key); cJSON_AddStringToObject(root, "query", query); cJSON_AddNumberToObject(root, "max_results", SEARCH_RESULT_COUNT); cJSON_AddBoolToObject(root, "include_answer", false); @@ -315,6 +314,9 @@ static esp_err_t tavily_search_direct(const char *query, search_buf_t *sb) esp_http_client_set_method(client, HTTP_METHOD_POST); esp_http_client_set_header(client, "Accept", "application/json"); esp_http_client_set_header(client, "Content-Type", "application/json"); + char auth[192]; + snprintf(auth, sizeof(auth), "Bearer %s", s_tavily_key); + esp_http_client_set_header(client, "Authorization", auth); esp_http_client_set_post_field(client, payload, strlen(payload)); esp_err_t err = esp_http_client_perform(client); @@ -347,9 +349,10 @@ static esp_err_t tavily_search_via_proxy(const char *query, search_buf_t *sb) "Host: api.tavily.com\r\n" "Accept: application/json\r\n" "Content-Type: application/json\r\n" + "Authorization: Bearer %s\r\n" "Content-Length: %d\r\n" "Connection: close\r\n\r\n", - (int)strlen(payload)); + s_tavily_key, (int)strlen(payload)); if (proxy_conn_write(conn, header, hlen) < 0 || proxy_conn_write(conn, payload, strlen(payload)) < 0) {