fix(ai): repair custom setting name autocompletion
All checks were successful
CI Code / Check spelling (pull_request) Successful in 13s
CI Code / Check coding style (pull_request) Successful in 23s
CI Code / Code Coverage (pull_request) Successful in 3m45s
CI Code / Linux (ubuntu) (pull_request) Successful in 5m24s
CI Code / Linux (arch) (pull_request) Successful in 7m7s
CI Code / Linux (debian) (pull_request) Successful in 8m41s
All checks were successful
CI Code / Check spelling (pull_request) Successful in 13s
CI Code / Check coding style (pull_request) Successful in 23s
CI Code / Code Coverage (pull_request) Successful in 3m45s
CI Code / Linux (ubuntu) (pull_request) Successful in 5m24s
CI Code / Linux (arch) (pull_request) Successful in 7m7s
CI Code / Linux (debian) (pull_request) Successful in 8m41s
The setting-name branch for /ai set custom never fired: it passed the prefix "/ai set custom " with a trailing space to autocomplete_param_with_ac(), which appends a space itself, so the matched prefix contained a double space no real input ever has. Even without that, the primitive completes the first token after the command while the setting name is the second, and the num_args guard only held before the name was started. The suggestion list (tools/search/memory/ plugins) predated the /ai set custom backend and matched no real payload parameter. Replace the branch with token-position completion (arg 5 via autocomplete_param_no_with_func) fed by a list rebuilt on demand from common payload parameters plus the keys already set on the provider, exposed through the new ai_get_provider_setting_keys() (snapshot taken under settings_lock). Drop the now-unused parse_args() call whose NULL result was fed to g_strv_length() unguarded, spamming a glib CRITICAL on TAB at /ai with zero or five-plus arguments.
This commit is contained in:
@@ -1192,11 +1192,6 @@ cmd_ac_init(void)
|
||||
autocomplete_add_unsorted(ai_api_types_ac, "responses", FALSE);
|
||||
autocomplete_add_unsorted(ai_api_types_ac, "auto", FALSE);
|
||||
|
||||
autocomplete_add_unsorted(ai_set_custom_subcommands_ac, "tools", FALSE);
|
||||
autocomplete_add_unsorted(ai_set_custom_subcommands_ac, "search", FALSE);
|
||||
autocomplete_add_unsorted(ai_set_custom_subcommands_ac, "memory", FALSE);
|
||||
autocomplete_add_unsorted(ai_set_custom_subcommands_ac, "plugins", FALSE);
|
||||
|
||||
autocomplete_add_unsorted(ai_remove_subcommands_ac, "provider", FALSE);
|
||||
|
||||
autocomplete_add(avatar_ac, "set");
|
||||
@@ -4545,17 +4540,61 @@ _ai_api_type_find(const char* const search_str, gboolean previous, void* context
|
||||
return autocomplete_complete(ai_api_types_ac, search_str, FALSE, previous);
|
||||
}
|
||||
|
||||
static char*
|
||||
_ai_custom_setting_find(const char* const search_str, gboolean previous, void* context)
|
||||
{
|
||||
return autocomplete_complete(ai_set_custom_subcommands_ac, search_str, FALSE, previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Autocomplete the setting name for /ai set custom <provider> <setting>.
|
||||
* Offers a few common payload parameters merged with the keys already set
|
||||
* on the provider, so existing settings can be retyped or overridden.
|
||||
*/
|
||||
static char*
|
||||
_ai_custom_setting_autocomplete(const char* const input, gboolean previous)
|
||||
{
|
||||
if (!g_str_has_prefix(input, "/ai set custom ")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Quote-aware parse: args[2] is the provider, args[3] the setting being
|
||||
* typed; skip the rebuild when the caret is not at the setting position */
|
||||
gboolean parse_result = FALSE;
|
||||
auto_gcharv gchar** args = parse_args(input, 1, 5, &parse_result);
|
||||
if (!parse_result) {
|
||||
return NULL;
|
||||
}
|
||||
guint num_args = g_strv_length(args);
|
||||
if (num_args < 3 || num_args > 4 || !ai_get_provider(args[2])) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Rebuild the completion list: common parameters + the provider's keys */
|
||||
gchar* suggestions[] = { "temperature", "max_tokens", "top_p" };
|
||||
GList* keys = ai_get_provider_setting_keys(args[2]);
|
||||
char** items = g_new0(char*, ARRAY_SIZE(suggestions) + g_list_length(keys) + 1);
|
||||
guint i = 0;
|
||||
for (; i < ARRAY_SIZE(suggestions); i++) {
|
||||
items[i] = suggestions[i];
|
||||
}
|
||||
for (GList* curr = keys; curr; curr = g_list_next(curr)) {
|
||||
items[i++] = curr->data;
|
||||
}
|
||||
autocomplete_update(ai_set_custom_subcommands_ac, items);
|
||||
g_free(items);
|
||||
g_list_free_full(keys, g_free);
|
||||
|
||||
/* /ai(1) set(2) custom(3) <provider>(4) <setting>(5) */
|
||||
return autocomplete_param_no_with_func(input, "/ai set custom", 5, _ai_custom_setting_find, previous, NULL);
|
||||
}
|
||||
|
||||
static char*
|
||||
_ai_autocomplete(ProfWin* window, const char* const input, gboolean previous)
|
||||
{
|
||||
char* result = NULL;
|
||||
|
||||
/* Parse once for reuse - /ai <subcommand> [<arg1>] [<arg2>] */
|
||||
gboolean parse_result = FALSE;
|
||||
auto_gcharv gchar** args = parse_args(input, 1, 4, &parse_result);
|
||||
int num_args = g_strv_length(args);
|
||||
|
||||
/* Top-level /ai <subcommand> autocomplete (e.g., /ai s<tab> -> /ai set) */
|
||||
// /ai set provider <name> <url> - autocomplete provider names (for updating)
|
||||
result = autocomplete_param_with_func(input, "/ai set provider", ai_providers_find, previous, NULL);
|
||||
if (result) {
|
||||
return result;
|
||||
@@ -4591,18 +4630,12 @@ _ai_autocomplete(ProfWin* window, const char* const input, gboolean previous)
|
||||
return result;
|
||||
}
|
||||
|
||||
// /ai set custom <provider> <setting> - autocomplete settings
|
||||
/* args[0]="set", args[1]="custom", args[2]=provider (if typed), args[3]=setting (if typed) */
|
||||
if (num_args == 3 && g_strcmp0(args[1], "custom") == 0) {
|
||||
/* /ai set custom <provider> - check if provider is valid */
|
||||
if (ai_get_provider(args[2])) {
|
||||
/* Valid provider, try settings autocomplete */
|
||||
result = autocomplete_param_with_ac(input, "/ai set custom ", ai_set_custom_subcommands_ac, TRUE, previous);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// /ai set custom <provider> <setting> - autocomplete setting names
|
||||
result = _ai_custom_setting_autocomplete(input, previous);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// /ai set <subcommand> - autocomplete subcommands
|
||||
result = autocomplete_param_with_ac(input, "/ai set", ai_set_subcommands_ac, TRUE, previous);
|
||||
if (result) {
|
||||
|
||||
Reference in New Issue
Block a user