fix(ai): unbreak CI and harden custom settings after chat-completions alignment #152
Reference in New Issue
Block a user
No description provided.
Delete Branch "fix/ai-chat-completions-followup"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Master CI is red since
9913344bb(chat-completions alignment): all 4 build flavors fail on two unit tests that still assert the removed legacy Perplexity"text"extraction (CI task 4817,RESULT: FAILED (builds 1 2 3 4)). This PR fixes the tests and, while in the area, hardens the/ai set custompayload path introduced by91631aa91, which could silently produce invalid JSON and race between threads.What was broken
test_ai_parse_response_perplexity_textandtest_ai_parse_response_text_preferred_over_contentassert the dropped/v1/agent"text" behavior;ai_parse_response()now extracts only chat-completions"content", so both fail andmake checkbreaks on every flavor._build_json_payload_from_list()emitted custom values JSON-escaped but unquoted:/ai set custom <p> reasoning_effort high→"reasoning_effort": high→ the whole request fails with a parse error on the provider side. Quoting manually could not work either, since the escaper rewrites"as\". Only numeric/boolean values could ever pass. The built-in/help aiexample (/ai set custom perplexity tools enabled) produced exactly this broken payload.provider->settings. The main thread mutates the hash via/ai set custom(g_hash_table_insert/remove) while the AI request thread iterates it withGHashTableIterwhen building the payload;session->lockdoes not cover the mutator. A concurrent insert can rehash under the iterator → undefined behavior.model/messages/streamduplicated the fixed payload fields with parser-dependent (last-wins) precedence: a customstreamwas silently ignored, a custommodelsilently overrode the standard one.ai_parse_response()header comment still described the Perplexity-first extraction; the payload docstring still said"input"; help example promoted a non-existent string param.Changes
1210daf35— fix(ai): harden custom settings payload against invalid JSON and races (src/ai/ai_client.{c,h},src/command/cmd_funcs.c,src/command/cmd_defs.c)true/false/null, validated by regex) bare; everything else as a quoted, escaped JSON string — every value is now representable and the payload is always valid JSON.model,messages,stream) inai_set_provider_setting()(now returnsgboolean;/ai set customshows an error) and skip them at payload-build time as a second line of defense for hand-edited prefs.settings_lock(pthread mutex): held by the mutator, the reader (ai_get_provider_setting) and the request-thread iteration. Lock order issession->lock→settings_lockon the worker only; the main thread takessettings_lockalone — no inversion./ai set custom perplexity temperature 0.7).ff0ec78e7— test(ai): align parse_response tests with chat completions API (tests/unittests/)test_ai_parse_response_perplexity_text→test_ai_parse_response_legacy_text_format_unsupported: the legacy nested format now yieldsNULLby design.test_ai_parse_response_text_preferred_over_content→test_ai_parse_response_content_preferred_over_text:"content"is authoritative now.test_ai_set_provider_setting_reserved_key: reserved keys rejected, ordinary keys still work.Testing
-Werror(autotools, Full flavor configure flags)."temperature": 0.7), strings quoted ("reasoning_effort": "high"), reserved keys never emitted.Notes
ff0ec78e78to5d7b7bb23d