Commit Graph

32 Commits

Author SHA1 Message Date
7cf82c99f0 fix(ai): destroy mutex and remove locking in unref
Some checks failed
CI Code / Check spelling (pull_request) Successful in 20s
CI Code / Check coding style (pull_request) Successful in 35s
CI Code / Code Coverage (pull_request) Failing after 1m9s
CI Code / Linux (debian) (pull_request) Failing after 2m48s
CI Code / Linux (ubuntu) (pull_request) Failing after 2m56s
CI Code / Linux (arch) (pull_request) Failing after 3m35s
2026-05-14 03:54:30 +00:00
f93f7cdf2c fix(ai): unlock mutex before early return in error callback
Some checks failed
CI Code / Check coding style (pull_request) Successful in 36s
CI Code / Check spelling (pull_request) Successful in 20s
CI Code / Code Coverage (pull_request) Failing after 1m9s
CI Code / Linux (debian) (pull_request) Failing after 2m45s
CI Code / Linux (arch) (pull_request) Failing after 3m32s
CI Code / Linux (ubuntu) (pull_request) Failing after 2m53s
The mutex was not released when the aiwin pointer was invalid, leading to a potential deadlock in the AI thread.
2026-05-14 03:52:20 +00:00
a9f0153c0f fix(ai): prevent duplicate user message in AI JSON payload
Some checks failed
CI Code / Check spelling (pull_request) Successful in 17s
CI Code / Check coding style (pull_request) Successful in 32s
CI Code / Code Coverage (pull_request) Failing after 1m9s
CI Code / Linux (debian) (pull_request) Failing after 2m53s
CI Code / Linux (ubuntu) (pull_request) Failing after 2m59s
CI Code / Linux (arch) (pull_request) Failing after 3m39s
The user message was being added to session->history before calling
_build_json_payload_from_list(), which independently appends the prompt
to the JSON payload. This caused the same message to appear twice in
the API request.

Fix: Build JSON payload first, then add user message to history under
the same lock to maintain atomicity.
2026-05-14 03:50:12 +00:00
b21d537e80 feat(ai): persist custom providers to config and move defaults to preferences
Some checks failed
CI Code / Check spelling (pull_request) Successful in 22s
CI Code / Code Coverage (pull_request) Failing after 1m12s
CI Code / Linux (debian) (pull_request) Failing after 3m13s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m21s
CI Code / Linux (arch) (pull_request) Failing after 4m1s
CI Code / Check coding style (pull_request) Failing after 13m40s
Fix /ai set provider <name> <url> not persisting across restarts.

- Add prefs_ai_set_provider(), prefs_ai_remove_provider(),
  prefs_ai_get_provider_url(), prefs_ai_list_providers(),
  prefs_free_ai_providers(), and prefs_ai_get_default_provider_url()
  to preferences.h/c for provider persistence.

- Move default provider URL definitions (openai, perplexity) from
  ai_client.c to preferences.c, following the established pattern
  where defaults are returned as fallbacks when no config value exists.

- Modify ai_add_provider() to persist new/updated providers to config.

- Modify ai_remove_provider() to remove provider from config.

- Add internal _ai_add_provider_nopersist() helper for adding default
  providers and loading from config without double-persisting.

- Update ai_client_init() to load custom providers from config on
  startup, allowing users to override defaults or add new ones.

Users now have full control: default providers remain as fallbacks,
user-added providers persist to config, and users can override or
remove defaults freely.
2026-05-13 18:28:35 +00:00
2f1637ca8e fix(ai): add reset for models_ac and streamline model autocomplete handling
Some checks failed
CI Code / Check spelling (pull_request) Successful in 22s
CI Code / Check coding style (pull_request) Successful in 36s
CI Code / Code Coverage (pull_request) Failing after 1m11s
CI Code / Linux (debian) (pull_request) Failing after 3m10s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m20s
CI Code / Linux (arch) (pull_request) Failing after 4m3s
Replace the custom ai_models_find function with a dedicated
ai_models_ac autocomplete list. Update the /ai switch trigger to
include a trailing space for consistent parsing.
2026-05-13 12:59:29 +00:00
1ecaceb59f fix(ai): reset provider autocomplete state on search string change
Some checks failed
CI Code / Code Coverage (pull_request) Failing after 12m29s
CI Code / Check spelling (pull_request) Failing after 13m4s
CI Code / Check coding style (pull_request) Failing after 13m36s
CI Code / Linux (ubuntu) (pull_request) Failing after 14m13s
CI Code / Linux (debian) (pull_request) Failing after 14m48s
CI Code / Linux (arch) (pull_request) Failing after 15m25s
When typing /ai start <prefix><tab>, the autocomplete was not properly
handling search string changes. For example, typing "/ai start o<tab>"
would return "openai", but then typing "/ai start p<tab>" would still
return "openai" because the autocomplete state was not reset.

This commit:
- Adds ai_providers_reset_ac() function to reset provider autocomplete
  state, following the same pattern as accounts_reset_all_search()
- Integrates ai_providers_reset_ac() into cmd_ac_reset() for proper
  state cleanup when user presses Ctrl+C or switches contexts
2026-05-13 09:40:52 +00:00
a75a06b4a2 Fix(ai): protect AI session state from concurrent access races
Some checks failed
CI Code / Check spelling (pull_request) Successful in 20s
CI Code / Check coding style (pull_request) Successful in 35s
CI Code / Linux (debian) (pull_request) Failing after 3m47s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m54s
CI Code / Code Coverage (pull_request) Successful in 6m41s
CI Code / Linux (arch) (pull_request) Failing after 9m31s
cmd_ai_switch() and cmd_ai_clear() mutated session fields (provider_name,
provider, model, api_key, history) on the main thread without coordination,
while _ai_request_thread() read the same fields concurrently in the worker
thread. This caused use-after-free when:

- g_free(session->model) was called between worker's read and g_strdup()
- ai_provider_unref(session->provider) freed the provider struct while
  worker accessed session->provider->api_url
- ai_session_clear_history() freed the history list while worker walked it

Fix:
1. Add pthread_mutex_t lock to AISession struct to protect all session
   fields from concurrent access.

2. Introduce ai_session_switch() public API that atomically switches
   provider, model, and API key under the session lock. This encapsulates
   all session mutations within ai_client.c so cmd_funcs.c never touches
   session fields directly.

3. Have _ai_request_thread() snapshot all session state under the session
   lock before making requests, using local copies for the duration of
   the curl request.

4. Add ai_provider_ref()/ai_provider_unref() around _ai_generic_request_thread()
   to prevent provider UAF during model-fetch requests.

5. Protect ai_session_add_message(), ai_session_clear_history(), and
   ai_session_set_model() with the session lock.

No pthread.h needed in cmd_funcs.c — all locking is encapsulated within
ai_client.c via the public API. No deadlock risk from nested locks.

Files changed:
- src/ai/ai_client.h: Add lock field, ai_session_switch() declaration
- src/ai/ai_client.c: Mutex init/destroy, session mutation protection,
  worker thread snapshot, provider ref management
- src/command/cmd_funcs.c: Use ai_session_switch() API, remove pthread.h
2026-05-11 23:42:24 +00:00
9f4621883a fix(ai): add mutex to AISession for thread safety
Some checks failed
CI Code / Linux (debian) (pull_request) Failing after 3m27s
CI Code / Linux (arch) (pull_request) Failing after 5m14s
CI Code / Code Coverage (pull_request) Failing after 10m52s
CI Code / Check spelling (pull_request) Failing after 10m57s
CI Code / Check coding style (pull_request) Failing after 11m2s
CI Code / Linux (ubuntu) (pull_request) Failing after 11m8s
Introduce a pthread mutex to protect all AISession fields from
concurrent access between the main thread and background request
worker.

- Initialize and destroy mutex during session lifecycle
- Lock session state when modifying or reading history, model, and
  provider fields
- Snapshot session state under lock in the request worker thread to
  prevent UAF races during API calls
- Refactor _build_json_payload to accept direct parameters for safe
  usage under lock
- Update command handlers to safely switch provider/model under lock
2026-05-11 23:26:14 +00:00
6fe8c370df ref(ai): remove org_id from provider configuration
Some checks failed
CI Code / Code Coverage (pull_request) Failing after 10m47s
CI Code / Check spelling (pull_request) Failing after 10m58s
CI Code / Check coding style (pull_request) Failing after 11m10s
CI Code / Linux (ubuntu) (pull_request) Failing after 11m30s
CI Code / Linux (debian) (pull_request) Failing after 11m42s
CI Code / Linux (arch) (pull_request) Failing after 11m54s
The org_id field was removed from AIProvider as it was no longer
populated through the command surface. The /ai set org command was
previously removed, leaving org_id as dead code.

This change removes org_id from:
- AIProvider struct definition
- ai_provider_new() and ai_provider_unref()
- ai_add_provider() API signature
- _build_curl_headers() (OpenAI-Organization header)
- cmd_ai_set() and cmd_ai_providers()
- All unit tests
2026-05-11 22:58:39 +00:00
b1dbe714e8 fix(ai): use atomic ai_provider_ref() in cmd_ai_switch
Some checks failed
CI Code / Linux (arch) (pull_request) Failing after 10m9s
CI Code / Code Coverage (pull_request) Failing after 14m6s
CI Code / Check spelling (pull_request) Failing after 14m27s
CI Code / Check coding style (pull_request) Failing after 14m44s
CI Code / Linux (ubuntu) (pull_request) Failing after 15m9s
CI Code / Linux (debian) (pull_request) Failing after 15m43s
src/command/cmd_funcs:11118 used a plain non-atomic ref_count++ on
ai_provider, which is a data race against concurrent
ai_provider_unref() calls using g_atomic_int_dec_and_test.

- Expose ai_provider_ref() in ai_client.h (was static)
- Replace non-atomic ref_count++ with ai_provider_ref() in cmd_ai_switch"
2026-05-11 21:15:10 +00:00
107f7778e2 fix(ai): collapse validate and dispatch into single critical section
Some checks failed
CI Code / Check spelling (pull_request) Successful in 31s
CI Code / Check coding style (pull_request) Successful in 43s
CI Code / Code Coverage (pull_request) Successful in 2m28s
CI Code / Linux (debian) (pull_request) Failing after 3m40s
CI Code / Linux (arch) (pull_request) Failing after 4m32s
CI Code / Linux (ubuntu) (pull_request) Failing after 6m18s
_aiwin_validate() no longer acquires the mutex. Callers now hold the
lock across both the existence check and the display dispatch,
eliminating the TOCTOU window where the window could be freed.
2026-05-11 20:54:42 +00:00
ecb07fd00c fix(ai): improve API error parsing and fallback
Some checks failed
CI Code / Check spelling (pull_request) Successful in 20s
CI Code / Check coding style (pull_request) Successful in 35s
CI Code / Code Coverage (pull_request) Successful in 2m32s
CI Code / Linux (debian) (pull_request) Failing after 3m37s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m48s
CI Code / Linux (arch) (pull_request) Failing after 4m40s
Add early return for empty responses and fallback to console output
when the AI window is closed or invalid. Implement JSON error
parsing to extract readable messages from API failures, improving
debugging and user feedback.
2026-05-09 21:06:09 +00:00
a898cb212d feat(ai): implement robust JSON model parsing
Some checks failed
CI Code / Check coding style (pull_request) Successful in 46s
CI Code / Linux (arch) (pull_request) Failing after 9m46s
CI Code / Code Coverage (pull_request) Failing after 14m8s
CI Code / Check spelling (pull_request) Failing after 14m16s
CI Code / Linux (ubuntu) (pull_request) Failing after 14m24s
CI Code / Linux (debian) (pull_request) Failing after 14m33s
Rewrote internal JSON parsing to correctly handle whitespace, escaped
quotes, and strict field context extraction. This prevents incorrect
field names or provider names from being added to the model list.

Added `ai_parse_models_from_json` public API to facilitate testing.

Changed `/ai models` default behavior to always fetch fresh models.
Replaced `--refresh` flag with `--cached` to display local cache.

Added comprehensive unit tests covering OpenAI and Perplexity formats,
array format, empty/null JSON, escaped quotes, and whitespace handling.
2026-05-09 13:56:59 +00:00
07d267b5bc fix(ai): protect window validation with mutex
Some checks failed
CI Code / Check coding style (pull_request) Successful in 53s
CI Code / Check spelling (pull_request) Successful in 19s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m49s
CI Code / Linux (arch) (pull_request) Failing after 4m31s
CI Code / Code Coverage (pull_request) Successful in 2m23s
CI Code / Linux (debian) (pull_request) Failing after 5m58s
The existence check accesses shared state without synchronization,
which can cause race conditions when called from background threads.
Explicitly locking the mutex ensures safe access during validation.
2026-05-09 13:20:48 +00:00
acae543057 feat(ai): add model caching, settings, and commands
Some checks failed
CI Code / Check spelling (pull_request) Successful in 23s
CI Code / Check coding style (pull_request) Successful in 35s
CI Code / Code Coverage (pull_request) Successful in 2m28s
CI Code / Linux (debian) (pull_request) Failing after 6m18s
CI Code / Linux (arch) (pull_request) Failing after 8m46s
CI Code / Linux (ubuntu) (pull_request) Failing after 11m4s
- Introduce model caching with persistence to preferences
- Add provider default model and custom settings management
- Implement `/ai switch`, `/ai models`, and improve `/ai start`
- Add model name autocomplete for chat commands
- Update command definitions and help text
- Add unit tests for new functionality
2026-05-09 13:15:58 +00:00
e229ed1281 fix(ai): return CURL_WRITEFUNC_ERROR on oversized response
Some checks failed
CI Code / Check coding style (pull_request) Successful in 1m4s
CI Code / Check spelling (pull_request) Successful in 1m10s
CI Code / Code Coverage (pull_request) Successful in 2m51s
CI Code / Linux (arch) (pull_request) Failing after 3m39s
CI Code / Linux (debian) (pull_request) Failing after 5m13s
CI Code / Linux (ubuntu) (pull_request) Failing after 5m21s
Return CURL_WRITEFUNC_ERROR instead of realsize when the response
exceeds 10MB. This causes curl to abort the transfer immediately
instead of continuing to stream data.
2026-05-01 19:15:46 +00:00
f133d81a05 fix(ai): use atomic operations for refcounting
Some checks failed
CI Code / Check coding style (pull_request) Successful in 1m8s
CI Code / Check spelling (pull_request) Successful in 1m7s
CI Code / Linux (debian) (pull_request) Failing after 2m58s
CI Code / Linux (arch) (pull_request) Failing after 3m7s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m8s
CI Code / Code Coverage (pull_request) Successful in 2m54s
Replace plain ref_count++/-- with g_atomic_int_inc and
g_atomic_int_dec_and_test for both AIProvider and AISession refcounts.
Prevents data races when ref/unref is called from worker threads.
2026-05-01 18:24:57 +00:00
a16237d16b fix(ai): convert \n escape sequences to actual newlines in LLM responses
Some checks failed
CI Code / Check spelling (pull_request) Successful in 51s
CI Code / Check coding style (pull_request) Successful in 1m7s
CI Code / Linux (debian) (pull_request) Failing after 2m56s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m5s
CI Code / Linux (arch) (pull_request) Failing after 3m5s
CI Code / Code Coverage (pull_request) Successful in 2m59s
2026-05-01 18:21:47 +00:00
cfe6ea46e2 feat(ai): disable request storage via store:false parameter
Some checks failed
CI Code / Check coding style (pull_request) Successful in 1m22s
CI Code / Linux (arch) (pull_request) Failing after 3m12s
CI Code / Check spelling (pull_request) Successful in 1m50s
CI Code / Linux (debian) (pull_request) Failing after 2m52s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m4s
CI Code / Code Coverage (pull_request) Successful in 2m49s
Add store:false to AI API requests to prevent OpenAI, Perplexity, and
other providers from storing conversation data or using it for training.

Both the OpenAI Responses API and Perplexity API support the store
parameter to control whether requests are persisted. Setting it to false
ensures conversations remain private and are not retained by the provider.

Privacy:
- Requests are not stored by AI providers
- Conversations are not used for model training
- Aligns with CProof's privacy-first design
2026-05-01 17:05:44 +00:00
2fc7f3d672 fix(ai): validate aiwin pointer to prevent UAF when window closed
Some checks failed
CI Code / Check spelling (pull_request) Successful in 53s
CI Code / Check coding style (pull_request) Successful in 1m11s
CI Code / Linux (debian) (pull_request) Failing after 2m58s
CI Code / Linux (arch) (pull_request) Failing after 3m11s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m10s
CI Code / Code Coverage (pull_request) Successful in 2m46s
Prevent use-after-free in the AI request worker thread when the user
closes the AI window during the 60-second HTTP request timeout. Without
this fix, the worker may dereference a dangling pointer and crash or
exhibit undefined behavior.

The _ai_request_thread function in ai_client.c previously cast user_data
to ProfAiWin* and used it directly without verifying the window was still
alive. Added wins_ai_exists() to iterate through all AI windows and check
if the pointer is still valid before use.

Safety:
- wins_ai_exists() iterates all AI windows (handles multiple AI windows)
- Worker skips UI update if window was freed, just cleans up
- Logs warning when dangling pointer is detected
2026-05-01 17:03:47 +00:00
fe0a46da58 refactor(ai): add UI display helpers
Some checks failed
CI Code / Check spelling (pull_request) Successful in 54s
CI Code / Check coding style (pull_request) Successful in 2m4s
CI Code / Linux (debian) (pull_request) Failing after 2m56s
CI Code / Linux (arch) (pull_request) Failing after 3m10s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m9s
CI Code / Code Coverage (pull_request) Successful in 2m55s
Add static _aiwin_display_error() and
_aiwin_display_response() helpers to reduce mutex repetition and
log warnings when aiwin is NULL or invalid.
2026-05-01 16:36:07 +00:00
cead417e78 refactor(ai): remove redundant callback layer from AI client
Some checks failed
CI Code / Check spelling (pull_request) Successful in 53s
CI Code / Check coding style (pull_request) Successful in 1m8s
CI Code / Linux (debian) (pull_request) Failing after 2m55s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m4s
CI Code / Linux (arch) (pull_request) Failing after 3m7s
CI Code / Code Coverage (pull_request) Successful in 2m42s
The ai_response_cb and ai_error_cb parameters were always passed the
same functions (aiwin_display_response and aiwin_display_error),
making the callback indirection redundant and complicating the call
chain.

Remove ai_callback_data_t, _ai_callback_invoke(), and
_ai_invoke_callback(). Simplify _ai_request_thread and ai_send_prompt
to directly call aiwin_display_error() and aiwin_display_response()
when user_data is a valid ProfAiWin*.
2026-05-01 13:34:00 +00:00
00f11eb704 fix(ai): guard NULL search_str and update tests for new cycling behavior
Some checks failed
CI Code / Check spelling (pull_request) Successful in 21s
CI Code / Check coding style (pull_request) Successful in 37s
CI Code / Linux (debian) (pull_request) Failing after 2m56s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m7s
CI Code / Code Coverage (pull_request) Successful in 2m55s
CI Code / Linux (arch) (pull_request) Failing after 3m45s
Update ai_providers_find() to handle NULL search_str safely by treating it
as an empty string, preventing a segfault in strdup() within autocomplete_complete().

Rename test_ai_providers_find_case_sensitive to test_ai_providers_find_case_insensitive
to reflect the new case-insensitive matching contract. Update all affected tests to
expect cycling behavior (NULL/empty returns first provider) and use auto_gchar for
automatic memory management.

Use `gchar` instead of `char` in ai_providers_find for consistency
2026-05-01 13:08:28 +00:00
634fb7d7eb fix(ai): standardize lock handling in _ai_invoke_callback
Some checks failed
CI Code / Check spelling (pull_request) Successful in 20s
CI Code / Check coding style (pull_request) Successful in 34s
CI Code / Code Coverage (pull_request) Failing after 1m6s
CI Code / Linux (debian) (pull_request) Failing after 2m59s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m11s
CI Code / Linux (arch) (pull_request) Failing after 3m19s
Take the global lock mutex before invoking all callbacks (success
and error) to ensure thread-safety. Previously some paths took the
lock and others did not, creating asymmetric behavior that could
lead to data races when callbacks access UI state.
2026-05-01 11:35:09 +00:00
461c0c32dd refactor(ai): use stateful autocomplete for provider name matching
Some checks failed
CI Code / Check spelling (pull_request) Successful in 57s
CI Code / Check coding style (pull_request) Successful in 1m4s
CI Code / Code Coverage (pull_request) Failing after 1m7s
CI Code / Linux (debian) (pull_request) Failing after 2m58s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m9s
CI Code / Linux (arch) (pull_request) Failing after 3m47s
Replace the manual GHashTable iteration in ai_providers_find() with the
existing stateful autocomplete system. Provider names are now kept in
sync via autocomplete_add/remove during ai_add_provider/ai_remove_provider,
and ai_providers_find delegates to autocomplete_complete() for deterministic
tab-completion cycling through sorted results.

This eliminates manual GList allocation, iteration, and cleanup, while
providing consistent forward/backward cycling behavior shared by all
autocomplete callers.
2026-04-30 23:16:12 +00:00
93ad7379e2 fix(ai): align ai_list_providers with documented contract
All checks were successful
CI Code / Check coding style (pull_request) Successful in 48s
CI Code / Check spelling (pull_request) Successful in 33s
CI Code / Linux (debian) (pull_request) Successful in 4m47s
CI Code / Linux (arch) (pull_request) Successful in 5m29s
CI Code / Code Coverage (pull_request) Successful in 2m45s
CI Code / Linux (ubuntu) (pull_request) Successful in 4m29s
Remove ai_provider_ref() from ai_list_providers() so the returned
providers do not need to be unref'd by the caller. This matches the
header docstring which states "caller must not free the list or
providers". Also update all callers (cmd_ai_providers, tests) to
remove redundant ai_provider_unref() calls.
2026-04-30 19:09:46 +00:00
caa0b3ccba fix(ai): remove redundant g_strdup on api_key assignment
Some checks failed
CI Code / Check coding style (pull_request) Successful in 37s
CI Code / Check spelling (pull_request) Successful in 21s
CI Code / Linux (arch) (pull_request) Failing after 3m12s
CI Code / Code Coverage (pull_request) Successful in 2m47s
CI Code / Linux (debian) (pull_request) Successful in 4m21s
CI Code / Linux (ubuntu) (pull_request) Successful in 4m53s
ai_get_provider_key() already returns a freshly g_strdup'd copy of
the API key. The outer g_strdup in ai_session_create() created an
unnecessary second copy, leaking the original pointer.
2026-04-30 19:06:49 +00:00
c9a5239117 fix(ai): remove API key from debug log
Some checks failed
CI Code / Check spelling (pull_request) Successful in 22s
CI Code / Check coding style (pull_request) Successful in 37s
CI Code / Linux (debian) (pull_request) Failing after 2m59s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m10s
CI Code / Code Coverage (pull_request) Successful in 2m58s
CI Code / Linux (arch) (pull_request) Failing after 3m59s
Remove the log_debug line in ai_client.c that leaked the first 10
characters of the API key into logs. This is also contained a memory leak (g_strndup
return value was never freed).
2026-04-30 19:05:33 +00:00
cff05ca802 ref(ai): move unfitting functions out of window.c; create aiwin.c
Some checks failed
CI Code / Check coding style (pull_request) Failing after 34s
CI Code / Check spelling (pull_request) Successful in 22s
CI Code / Linux (arch) (pull_request) Failing after 2m57s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m16s
CI Code / Linux (debian) (pull_request) Failing after 6m16s
CI Code / Code Coverage (pull_request) Successful in 7m12s
2026-04-30 18:01:24 +00:00
9c8ad57b59 ref(ai): add stub, fix includes, move aiwin_send_message location
Some checks failed
CI Code / Check spelling (pull_request) Successful in 22s
CI Code / Check coding style (pull_request) Successful in 34s
CI Code / Linux (debian) (pull_request) Failing after 2m57s
CI Code / Linux (ubuntu) (pull_request) Failing after 3m9s
CI Code / Linux (arch) (pull_request) Failing after 3m13s
CI Code / Code Coverage (pull_request) Successful in 2m54s
2026-04-30 17:41:36 +00:00
1f1770bd58 fix(ai): set correct links in tests, fix headers 2026-04-30 17:02:54 +00:00
e43e8378b0 feat(ai): add AI client with multi-provider support and UI
Some checks failed
CI Code / Check coding style (pull_request) Successful in 47s
CI Code / Check spelling (pull_request) Successful in 59s
CI Code / Code Coverage (pull_request) Failing after 1m8s
CI Code / Linux (debian) (pull_request) Failing after 2m28s
CI Code / Linux (ubuntu) (pull_request) Failing after 2m41s
CI Code / Linux (arch) (pull_request) Failing after 3m15s
Add an AI client module that integrates with OpenAI-compatible API
providers (OpenAI, Perplexity, and custom providers) to provide
AI-assisted responses within the profanity client.

The implementation includes:

- src/ai/ai_client.c/h: Core AI client with provider management,
  session handling, and async HTTP request handling via libcurl.
  Supports per-provider API keys stored in preferences, reference-
  counted sessions, and conversation history tracking.

- src/ui/window.c/window_list.c: New AI window type (ProfAiWin) for
  displaying AI conversations, with response streaming and error
  display capabilities.

- Command integration: New `/ai` command (cmd_defs.c, cmd_funcs.c)
  for creating sessions, sending prompts, and managing providers.
  Provider autocomplete support in cmd_ac.c.

- Preferences integration: API keys for providers are persisted in
  the preferences system (config/preferences.c).

- Unit tests: 472 lines of comprehensive tests covering provider
  management, session lifecycle, JSON escaping, and autocomplete
  (tests/unittests/test_ai_client.c).

Architecture decisions:
- Asynchronous design: HTTP requests run on a separate thread to
  avoid blocking the main UI loop. Callbacks are invoked on the main
  thread via direct function call (profanity uses ncurses, not GLib
  main loop).
- Reference counting: Both AIProvider and AISession use ref counting
  for safe shared ownership.
- Response size limit: 10MB cap on HTTP responses to prevent OOM.
2026-04-29 19:23:33 +00:00