Skip to content

Use the Logos Chat module API from an app#365

Merged
kashepavadan merged 10 commits into
mainfrom
chat-module-api
Jul 6, 2026
Merged

Use the Logos Chat module API from an app#365
kashepavadan merged 10 commits into
mainfrom
chat-module-api

Conversation

@kashepavadan

Copy link
Copy Markdown
Contributor

From: #311

@danisharora099 danisharora099 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice tutorial — clear structure and the API details hold up. I cross-checked every event name, argument order, and the init() signature against chat_module.lidl at v0.1.1, and the dependency_overrides block matches what logos-chat-ui actually ships, so no surprises there.

One thing I think blocks merge: the flake.nix in Step 2 is missing the delivery_module runtime input, so if someone follows this start to finish it won't build. Details in the inline comment. A handful of smaller things too, mostly consistency and "how do I know it worked" stuff.

```nix
inputs = {
logos-module-builder.url = "github:logos-co/logos-module-builder";
chat_module.url = "github:logos-co/logos-chat-module/v0.1.1";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(blocker) This snippet is missing a piece and the build won't resolve delivery_module.

metadata.json lists delivery_module as a dependency, and the module builder pulls each dependency's runtime from a matching flake input — but here the only input is chat_module. The dependency_overrides entry only points the builder at delivery's .lidl contract for codegen; it doesn't supply the runtime build. So nix build has nothing to resolve delivery_module against.

logos-chat-ui handles this by pinning delivery separately and passing it in:

logos-delivery-module.url = "github:logos-co/logos-delivery-module/<rev>";
# then: flakeInputs = { delivery_module = logos-delivery-module; } // inputs;

Could we add that to the snippet? One heads-up while you're in there: logos-chat-ui deliberately pins a commit past v0.1.2 to pick up the zerokit/RLN build fix (the v0.1.2 tag trips over a crates.io 403 during the Rust build). Worth a warning so people don't pin the tag and get stuck.


## Step 4: Drive the chat lifecycle

Status-bearing methods return their result **synchronously** as a `LogosResult`: `res.success` tells you whether the call succeeded, `res.getError<QString>()` carries the failure reason, and `res.getValue<QString>()` carries the returned value (for example, the intro bundle). Ongoing activity — incoming messages, new conversations, delivery-state changes — arrives asynchronously through the push events you subscribed to in Step 3.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small thing that'll bite copy-pasters: here we use res.getError<QString>() / res.getValue<QString>(), but the Delivery API doc uses r.getError() / r.getString() for the same LogosResult type. Someone reading both will hit a compile error on one of them. Do you know which form the SDK actually exposes? Would be good to line the two docs up.

```

- The initiator calls `create_conversation` with the peer's intro bundle and a plain-text opening message.
- The recipient does not call anything; a `conversation_created` push event (`is_outgoing == false`) arrives automatically, followed by a `message_received` event.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole point here is two instances talking to each other, but the tutorial stops at "send a message" without showing the reader how to run two instances, swap intro bundles, and see a message land. logos-chat-ui already has this (nix run .#exchange / two-instance-exchange.md). Even a short "run a second instance, paste its bundle, you should see a message_received event" section — or just linking that flow as the verification step — would close the loop.

nix build
```

1. Preview the module using `logos-standalone-app` (for `ui_qml` modules):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Step 5 says to preview the module in logos-standalone-app, but since we scaffold the backend template, delete the example UI, and only wire up the C++ chat logic, there's nothing visible to actually preview. Might be worth a line in "What to expect" saying this is the backend pattern and pointing at logos-chat-ui for a full wired UI, so nobody's surprised when nix run doesn't show a chat window.

title: Build a Logos module that uses the Chat module API
doc_type: procedure
product: messaging
topics: []

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authors and topics are both empty here — the Delivery doc fills them in (authors: igor-sirotin, kashepavadan, topics: delivery). Mind adding yourself as author and a topic like chat?


```cpp
// content is plain text — no encoding required.
const LogosResult res = m_logos->chat_module.create_conversation(peerBundle, "Hello!");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: the contract also has set_conversation_nickname and delete_conversation, and they're what fire the conversation_updated / conversation_deleted events the doc already covers. A one-liner pointing at them would help anyone who wants to rename or delete a conversation.

|---|---|---|
| `instance_path` | string | Directory for this instance's persistent state (`identity.db`, `history.json`). Use a distinct directory per instance to run several side by side. |
| `delivery_preset` | string | Network preset for the delivery node. Use `logos.test` to reach the Logos test network. Must match across all participants. |
| `tcp_port` | int | Logos Delivery (Waku) TCP port. `0` picks a random port. |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit, totally optional) the tcp_port note calls it the "Logos Delivery (Waku) TCP port." If the docs generally keep Waku under the hood, might want to drop it; if not, ignore me.

@igor-sirotin

Copy link
Copy Markdown
Contributor

Pardon, I'm still working on the last commit that I pushed yesterday

kashepavadan and others added 3 commits July 2, 2026 15:26
v0.1.1 reimplements chat_module as a Rust SDK module with the typed
chat_module.lidl contract over Logos Core IPC, replacing the v0.1.0 C++
plugin. Align the tutorial with how logos-chat-ui consumes it:

- pin chat_module to v0.1.1; declare delivery_module + dependency_overrides
- synchronous LogosResult return model instead of async *Result events
- new init(instance_path, delivery_preset, tcp_port) signature (no JSON config)
- snake_case methods (create_intro_bundle, create_conversation, send_message,
  shutdown) and typed push events (message_received, conversation_created, ...)
- plain-text content (drop hex encoding); persistent identity/history

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kashepavadan

Copy link
Copy Markdown
Contributor Author

Take a look now please @danisharora099

@weboko weboko left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review after the v0.1.2 rewrite — dogfooded on Linux x86_64.

I re-ran this end to end against the pinned upstream sources and a real Nix scaffold. Nice work on the rewrite — the earlier blocker is properly closed:

  • delivery_module runtime wiring (previous blocker): Step 2 now pins logos-delivery-module to v0.1.3 and maps it in via flakeInputs = { delivery_module = logos-delivery-module; } // inputs;. I diffed this against logos-chat-ui's flake.nix@v0.1.2 and it's the same wiring. I scaffolded a fresh module from tutorial-v3#ui-qml-backend, applied Step 2 verbatim, and nix flake metadata locks all inputs cleanly (chat_module@v0.1.2, logos-delivery-module@v0.1.3, full builder tree resolve). The v0.1.3/RLN-403 rationale in the hint matches delivery-module #49.
  • Two-instance verification (Step 6) added — closes the "stops at send a message" gap.
  • API surface verified: every method, the init(instance_path, delivery_preset, tcp_port) signature, and all six events (names + argument order) match chat_module.lidl@v0.1.2 exactly.
  • ℹ️ On the getError<QString>() vs getString() question from last round: this doc's form (res.getError<QString>() / res.getValue<QString>()) is the correct one — it's exactly what the shipping ChatBackend.cpp@v0.1.2 uses. The divergence is on the Delivery doc side (r.getError() / r.getString()), so nothing to change here — worth aligning that doc in a follow-up instead.

Three inline items left below: one snippet that won't compile as written (worth fixing), plus the two frontmatter/preview nits from last round that are still open. Not blocking beyond the compile-bug fix.

Comment thread docs/messaging/chat-module/build-logos-module-that-uses-chat-module-api.md Outdated
Comment thread docs/messaging/chat-module/build-logos-module-that-uses-chat-module-api.md Outdated
nix build
```

1. Preview the module using `logos-standalone-app` (for `ui_qml` modules):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still open from last round: since Step 1 deletes the example UI and this guide only wires the C++ chat backend, nix run launches the standalone host with no chat window — which surprises readers who expect a visible chat. A one-line heads-up here (or in What to expect) closes that gap:

Suggested change
1. Preview the module using `logos-standalone-app` (for `ui_qml` modules):
1. Preview the host with `logos-standalone-app` (for `ui_qml` modules). Because Step 1 removed the example UI and this guide only wires up the C++ chat backend, `nix run` starts the host but shows no chat window — that's expected. For a fully wired reference UI, see [`logos-chat-ui`](https://github.com/logos-co/logos-chat-ui/tree/v0.1.2):

@weboko weboko left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up: I actually ran nix build (Step 5) end to end, and following the doc literally fails.

I installed Nix, scaffolded from tutorial-v3#ui-qml-backend, ran the Step 1.4 rm, applied Step 2, and ran nix build. It fails at CMake configure:

CMake Error at .../cmake/LogosModule.cmake:602 (file):
  file failed to open for reading (No such file or directory):
    .../src/ui_example.rep

Root cause: Step 1.4 deletes the four ui_example.* files, but the scaffold's CMakeLists.txt still hardcodes them, and metadata.json still names the module ui_example:

logos_module(
    NAME ${MODULE_NAME}            # metadata.json "name" = "ui_example"
    REP_FILE src/ui_example.rep    # <- deleted in Step 1.4
    SOURCES
        src/ui_example_interface.h # <- deleted
        src/ui_example_plugin.h    # <- deleted
        src/ui_example_plugin.cpp  # <- deleted
)

So deleting the sources without re-pointing CMakeLists.txt + metadata.json (and supplying your own plugin sources) guarantees a hard build break in Step 5 — the reader never reaches nix build successfully. The suggestion on line 63 makes the missing steps explicit; happy to iterate on the exact wording. (Everything else — Step 1 scaffold, Step 2 flake wiring, input lock — worked; this is the one gap that stops the happy path.)

git init && git add -A
```

1. Remove the template's example sources. The scaffolded template includes `ui_example` files with mismatched class names and IIDs; leaving them causes build errors or plugin-load failures at runtime:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This step is where the happy path breaks. Deleting these files while CMakeLists.txt (REP_FILE / SOURCES) and metadata.json (name, main) still reference ui_example makes nix build fail at configure. The step needs to also cover re-pointing those two files and adding your own plugin sources:

Suggested change
1. Remove the template's example sources. The scaffolded template includes `ui_example` files with mismatched class names and IIDs; leaving them causes build errors or plugin-load failures at runtime:
1. Replace the template's example sources with your own. The scaffold's `CMakeLists.txt` (`REP_FILE` / `SOURCES`) and `metadata.json` (`name`, `main`) both reference `ui_example`, so simply deleting these files makes `nix build` (Step 5) fail at CMake configure with `file failed to open for reading: src/ui_example.rep`. Delete the examples, then create your own `src/<name>.rep`, `src/<name>_interface.h`, and `src/<name>_plugin.{h,cpp}` (Step 3 supplies the plugin body) and update `CMakeLists.txt` and `metadata.json` (`name`, `main`) to point at them:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@igor-sirotin Is there an easier way to deal with this issue?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@weboko thanks for the catch!
@kashepavadan I've addressed this in c49e216, please take a look

Co-authored-by: Sasha <118575614+weboko@users.noreply.github.com>

@weboko weboko left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I re-dogfooded this tutorial end-to-end on a clean Ubuntu 24.04 box after the latest commit: installed Nix + flakes, scaffolded from tutorial-v3#ui-qml-backend, added the Step 2 dependencies (chat_module v0.1.2 + logos-delivery-module v0.1.3), and ran nix build.

Good news: Step 2's delivery wiring now resolves correctly. nix flake lock pulls delivery_module from the logos-delivery-module v0.1.3 input via flakeInputs, and the earlier "can't resolve delivery_module" blocker is gone. The topics/authors, the intro-bundle snippet, and the new Step 6 from the last round all look addressed too.

One blocker remains — Step 1.4 (inline comment below). It's the same spot @weboko flagged and @kashepavadan asked about; I've reproduced the exact failure and verified a minimal fix.

Comment on lines +63 to +67
1. Remove the template's example sources. The scaffolded template includes `ui_example` files with mismatched class names and IIDs; leaving them causes build errors or plugin-load failures at runtime:

```bash
rm -f src/ui_example.rep src/ui_example_interface.h src/ui_example_plugin.h src/ui_example_plugin.cpp
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(blocker, reproduced) Following this step literally makes nix build fail at the CMake configure step.

tutorial-v3#ui-qml-backend scaffolds a coherent, buildable plugin — src/ui_example.rep + src/ui_example_plugin.* — and both CMakeLists.txt (REP_FILE/SOURCES, line 21) and metadata.json (main) reference it. The rm here deletes those files but leaves the references, so nix build dies at configure:

CMake Error at .../cmake/LogosModule.cmake:602 (file):
  file failed to open for reading (No such file or directory):
    .../src/ui_example.rep
Call Stack (most recent call first):
  .../LogosModule.cmake:577 (_logos_module_add_replica_factory)
  CMakeLists.txt:21 (logos_module)
-- Configuring incomplete, errors occurred!

I verified the easiest fix is to keep the scaffolded plugin and wire the chat logic into its existing initLogos() in Step 3. With the files kept + the Step 2 dependencies added:

  • nix build → produces ui_example_plugin.so
  • nix build .#lgx (Step 5) → produces the .lgx
  • adding the Step 3/4 LogosModules / chat_module calls into initLogos() compiles and links cleanly against the generated logos_sdk.h ([13/16] ui_example_plugin.cpp[16/16] Linking ui_example_plugin.so, exit 0).

Also, the current rationale ("mismatched class names and IIDs; leaving them causes build errors or plugin-load failures") doesn't hold for tutorial-v3 — the example plugin's class names and IID (org.logos.UiExampleInterface) are internally consistent and build fine. It's the deletion, not the example files, that breaks the build.

Suggested replacement for this step:

Suggested change
1. Remove the template's example sources. The scaffolded template includes `ui_example` files with mismatched class names and IIDs; leaving them causes build errors or plugin-load failures at runtime:
```bash
rm -f src/ui_example.rep src/ui_example_interface.h src/ui_example_plugin.h src/ui_example_plugin.cpp
```
1. **Keep the scaffolded plugin — don't delete it.** In `tutorial-v3#ui-qml-backend` the generated `src/ui_example.rep` and `src/ui_example_plugin.*` are a coherent, buildable plugin that `CMakeLists.txt` (`REP_FILE`/`SOURCES`) and `metadata.json` (`main`) already reference; you'll wire the chat logic into its `initLogos()` in Step 3. Deleting these files without also re-pointing `CMakeLists.txt` and `metadata.json` breaks `nix build` at the CMake configure step (`file failed to open for reading … src/ui_example.rep`). To give the module its own name, **rename** the four `src/ui_example*` files and update the matching `REP_FILE`/`SOURCES` in `CMakeLists.txt` and `main` in `metadata.json` to match — don't remove them outright.

Step 1.4 told readers to delete the scaffold's ui_example sources, but
CMakeLists.txt and metadata.json still reference them, so `nix build`
(Step 5) failed at CMake configure. Reframe the step to keep and build on
the example instead of deleting it, and keep the module name consistent:

- Step 1.4: keep the generated files; explain what each is and where chat
  code goes, with a table for readability.
- Step 2: keep metadata name as `ui_example` (was `my_app`, which would
  break the `logos.module("ui_example")` binding in Main.qml).
- Step 3: point initLogos() at the real UiExamplePlugin class and preserve
  the scaffold's existing `logosAPI = api;` / `setBackend(this);` lines.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@weboko weboko left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dogfooded end-to-end on Linux (headless) — one build-breaking issue found

I followed this tutorial from scratch on a clean Ubuntu 24.04 box: installed Nix (flakes), scaffolded via nix flake init -t github:logos-co/logos-module-builder/tutorial-v3#ui-qml-backend, applied Step 2 (metadata.json + flake.nix with chat_module v0.1.2 / logos-delivery-module v0.1.3), and wrote the Step 3–4 chat code into ui_example_plugin.{h,cpp}.

What works ✅

  • nix build succeeds — ui_example_plugin.so links with the chat code (initLogos present), delivery wrapper auto-generated, lidl tests 17/17.
  • nix build .#lgx succeeds — produces logos-ui_example-module.lgx.
  • The documented API surface (methods, event arg orders, init(instance_path, delivery_preset, tcp_port)) matches chat_module.lidl at v0.1.2 exactly.
  • The Step 1.4 "keep the generated files / keep the name ui_example" fix from the latest commit is correct and builds cleanly.

What breaks ❌ (Step 3.1)
Following Step 3.1 literally does not compile. The snippet places #include "logos_sdk.h" in the .cpp, but instructs adding the member LogosModules* m_logos to the header (src/ui_example_plugin.h). The header then has no visibility of LogosModules, so the build fails:

src/ui_example_plugin.h:36:5: error: 'LogosModules' does not name a type; did you mean 'LogosMode'?
   36 |     LogosModules* m_logos = nullptr;
src/ui_example_plugin.cpp:19:5: error: 'm_logos' was not declared in this scope

The fix is to put the include in the header (where the member is declared); the .cpp picks it up transitively via #include "ui_example_plugin.h". With the include in the header, nix build passes (that's the variant I built above). Suggested change inline.

Note: Step 6's live two-instance exchange over logos.test requires a GUI (logos-standalone-app) + network peers, so I validated the build/package path (Steps 1–5) rather than the runtime round-trip; nix run is still building the standalone app in this headless env.

Comment on lines +135 to +138
#include "logos_sdk.h" // generated umbrella — exposes LogosModules

// Add a member to your plugin class (src/ui_example_plugin.h):
// LogosModules* m_logos = nullptr;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Build-breaking as written. The #include belongs in the header, not the .cpp — the LogosModules* m_logos member is declared in src/ui_example_plugin.h, so the type must be visible there. As written the header fails with 'LogosModules' does not name a type. Verified: moving the include into the header makes nix build pass.

Suggested change
#include "logos_sdk.h" // generated umbrella — exposes LogosModules
// Add a member to your plugin class (src/ui_example_plugin.h):
// LogosModules* m_logos = nullptr;
// Put this include in your plugin **header** (`src/ui_example_plugin.h`),
// next to the `m_logos` member below — `LogosModules` must be a complete
// type where the member is declared. The `.cpp` picks it up transitively
// via its `#include "ui_example_plugin.h"`. Including it only in the `.cpp`
// leaves the header failing with `error: 'LogosModules' does not name a type`.
#include "logos_sdk.h" // generated umbrella — exposes LogosModules
// Add a member to your plugin class (src/ui_example_plugin.h):
// LogosModules* m_logos = nullptr;

The snippet put `#include "logos_sdk.h"` in the .cpp while declaring the
`LogosModules* m_logos` member in the header, so the header saw no
declaration of `LogosModules` and failed to compile
(`'LogosModules' does not name a type`). Split the snippet into a header
block (include + member) and a cpp block (construction), so the type is
visible where the member is declared.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@weboko weboko left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dogfooded this guide end-to-end on the current revision (head e075c13) — the build path is solid now.

Installed Nix + flakes and ran every step verbatim on a clean machine:

  • Step 1 scaffold (nix flake init -t …#ui-qml-backend) — generated files match the Step 1.4 table.
  • Step 2 deps — metadata.json + flake.nix exactly as written; delivery_module resolves and the logos-delivery-module/v0.1.3 pin builds. The earlier "delivery_module won't resolve" blocker no longer reproduces.
  • Step 3 — header #include "logos_sdk.h" + the LogosModules* m_logos member + all six chat.on(...) subscriptions compile. The header/cpp include-split fix holds.
  • Step 5nix build produces the module; nix build .#lgx produces logos-ui_example-module.lgx.
  • API accuracy — every method, event name, argument order, and the Status { convo_count, delivery_state, detail } shape in Steps 3–4 match chat_module v0.1.2's rust-lib/chat_module.lidl exactly (verified against the generated chat_module_api.h).

One doc-level gap remains in Step 6 — it isn't executable with the tutorial's own hardcoded instance_path (inline comment below).

Note: nix run triggers a from-source rebuild of liblogosdelivery; in my sandbox that hit a TLS/proxy snag fetching a transitive cargo git dep — environmental, not a doc issue.

Comment thread docs/messaging/chat-module/build-logos-module-that-uses-chat-module-api.md Outdated

## Step 6: Verify a two-instance exchange

A chat is only proven end to end when a message travels between two running instances. Start two copies of your module — each with its own `instance_path` and `tcp_port` — and confirm a message lands as a `message_received` event.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As written, Step 6 can't be run with the tutorial's own code, because instance_path is fixed in initLogos() (see the suggestion on the init() line) — there's no documented way to give two nix run instances distinct directories. Worth either parameterizing instance_path per the suggestion above, or pointing readers at the ready-made two-instance harness in logos-chat-ui (nix run .#exchange).

@weboko

weboko commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Follow-up on the nix run caveat in my review above — I got it working, so Step 5 is fully validated end to end.

nix run compiles the standalone host + chat_module/delivery_module from source (the initial failure was my sandbox's proxy TLS on a transitive cargo git dep — environmental, not the doc). Once past that, the host launches and loads the module set cleanly:

[logos] Module loaded: capability_module
[logos] Module loaded: delivery_module
[logos] Module loaded: chat_module
[delivery_module] DeliveryModuleImpl: Initialized successfully

So the full path in this guide — scaffold → Step 2 deps → Step 3/4 code → nix buildnix build .#lgxnix run — all works against chat_module v0.1.2 as written. The only remaining doc gap is the hardcoded instance_path blocking Step 6 (inline comment above).

kashepavadan and others added 2 commits July 6, 2026 17:30
…odule-api.md

Co-authored-by: Sasha <118575614+weboko@users.noreply.github.com>
@kashepavadan kashepavadan merged commit 8b02a17 into main Jul 6, 2026
@kashepavadan kashepavadan deleted the chat-module-api branch July 6, 2026 21:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants