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.
- Add 8 tests for disco info and disco items commands
- Fix XEP-0030 compliance bug: show message for empty disco#items results
- Tests cover: identity display, features, server/jid queries, error handling,
items display, empty results, and connection requirement
Major changes:
Run 4 build configurations in parallel with Valgrind on Linux
Add test failure detection verification (meta-test)
Port allocation per build to prevent conflicts in parallel runs
Add --coverage-only flag for dedicated coverage builds
Code quality:
Add TEST_GROUPS constant, CMOCKA patterns, helper functions
Organize ci-build.sh into sections
Split functional tests into 4 parallel groups and add check-functional-parallel target (~3x faster CI runs).
Add branch-aware LCOV coverage reporting with new --enable-coverage option and lcov summary in CI pipeline.
Enable ccache via -C configure flag for faster recompilations.
Install lcov in all Docker images and use --depth 1 git clones + parallel make -j$(nproc) for quicker container builds.
Update CONTRIBUTING.md with instructions for parallel test groups and adding new ones.
All changes are tightly related CI/performance improvements developed in sequence. No external service uploads (e.g. Codecov skipped due to Gitea incompatibility).
As 9f2abc75 accidentally got the ordering of some of the includes wrong,
I decided to propose my initial solution again.
Additional to that, I've opened a MR against CMocka to solve this on
their side, since I believe that the current way this is done is not
sustainable [0].
[0] https://gitlab.com/cmocka/cmocka/-/merge_requests/91
Fixes: 9f2abc75 ("Fix tests with gcc15 (uintptr_t)")
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
CProof note: our new tests need to also be updated.
* Also pass `$*` to `configure` when invoking `ci-build.sh`, so one can
e.g. run `./ci-build.sh --without-xscreensaver`
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
While trying to get the unit tests working again I stumbled over all those
things that I thought could be better^TM.
Now we also know "TODO: why does this make the test fail?" - because
the unit tests are brittle AF ... and we have to init the subsystems
we use in the test, otherwise the cleanup will fail...
BTW. you can now also only run a single test ... or a pattern or so ...
you'd have to read how `cmocka_set_test_filter()` works exactly.
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
Revert "Merge pull request #1943 from H3rnand3zzz/gmainloop
This reverts commit 609fde0998, reversing
changes made to 2ec94064ed.
Revert "Merge pull request #1948 from H3rnand3zzz/fix/rl-less-refreshes"
This reverts commit 11762fd2b0, reversing
changes made to 609fde0998.
We have got several issues, that we don't quite see how to solve, with
the merge of the gmainloop PR.
* Slashguard is broken (#1955) (though #1956 could fix that)
* One person reported problems with copy paste selection via mouse
* Some input buffer seems not to be cleared correctly
It happened that I was debugging profanity used `/connect` and typed
the password. I then debugged so long that a time out occurred, so
profanity disconnected. Then it printed "unknown command: $password".
There was something else that I forgot now.
Bottomline is: so far we didn't get it right so we will undo these
changes until someone proposes a working solution.
We got a slight performance increase (apparently noticable when
alt+mouse scrolling) but got too many issues with this change.
Only nicknames, photos, birthdays, addresses, telephone numbers, emails,
JIDs, titles, roles, notes, and URLs are supported
Due to the synopsis array not having enough space, `/vcard photo
open-self` and `/vcard photo save-self` are not documented properly in
the synopsis section of the `/vcard` command, but they are documented in
the arguments section
Fixed memory leak in vcard autocomplete (thanks to debXwoody)
The profanity-internal mechanism to allow connecting to a server isn't
easily portable to cURL. Therefor introduce a profanity-specific CAfile
which is managed individually and will be configured in libcurl calls.
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
src/pgp/gpg.c:p_ox_gpg_readkey
Used to read a public key from a file. The function will return the fingerprint
of the file and the base64 encoded key.
src/xmpp/ox.[hc]
ox_announce_public_key(const char* const filename) can be called from the /ox
announce <filename> command. The key within the file will be pushed on PEP and
the Metadata node will be set.
Issue: #1331
I plan to save all messages in an SQLite db.
For retrieving information it's nicer than having it in a text file.
We will have more info in there and easier to parse it.
This will also be good for later MAM
(https://github.com/profanity-im/profanity/issues/660).
Regular text files will still be an option for users so that they can
easily grep them and do whatever they like.
Internally Profanity will only use the SQLite db.