Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
BasedOnStyle: Google
Language: Cpp
Standard: c++17

ColumnLimit: 110
SpacesBeforeTrailingComments: 1
AccessModifierOffset: -2
17 changes: 17 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
# Pragmatic checks for the SDK. Third-party headers (LiveKit, IXWebSocket,
# nlohmann) are excluded via HeaderFilterRegex.
Checks: >
-*,
bugprone-*,
performance-*,
modernize-use-override,
modernize-use-nullptr,
modernize-use-using,
readability-redundant-*,
-bugprone-easily-swappable-parameters,
-bugprone-exception-escape

WarningsAsErrors: ''
HeaderFilterRegex: '.*/(include|src)/decart/.*|.*/src/detail/.*|.*/src/realtime/.*'
FormatStyle: file
62 changes: 62 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: CI

on:
push:
branches: [main]
pull_request:

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
name: build & test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-14, windows-latest]
env:
# Used by cmake/LiveKitSDK.cmake to resolve & download the LiveKit release.
GITHUB_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v4

- name: Install build tools (Linux)
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y ninja-build libssl-dev zlib1g-dev

- name: Install build tools (macOS)
if: runner.os == 'macOS'
run: brew install ninja

- name: Configure & build (Unix)
if: runner.os != 'Windows'
run: |
cmake -B build -S . -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DDECART_BUILD_EXAMPLES=ON -DDECART_BUILD_TESTS=ON
cmake --build build

- name: Configure & build (Windows, vcpkg)
if: runner.os == 'Windows'
shell: pwsh
run: |
cmake -B build -S . `
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" `
-DVCPKG_MANIFEST_FEATURES=tests `
-DDECART_BUILD_EXAMPLES=ON -DDECART_BUILD_TESTS=ON
cmake --build build --config Release

- name: Test
run: ctest --test-dir build --output-on-failure -C Release

format:
name: clang-format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check formatting
run: |
sudo apt-get update && sudo apt-get install -y clang-format
./scripts/format.sh --check
33 changes: 33 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Release

on:
push:
tags:
- "v*"

permissions:
contents: write

jobs:
release:
name: Create GitHub release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Verify tag matches CMake project version
run: |
tag="${GITHUB_REF_NAME#v}"
proj="$(sed -n 's/^[[:space:]]*VERSION[[:space:]]*\([0-9][0-9.]*\).*/\1/p' CMakeLists.txt | head -1)"
echo "tag=$tag project=$proj"
if [ "$tag" != "$proj" ]; then
echo "::error::Tag v$tag does not match CMake project version $proj"
exit 1
fi

- name: Create release with autogenerated notes
env:
GH_TOKEN: ${{ github.token }}
run: gh release create "${GITHUB_REF_NAME}" --title "${GITHUB_REF_NAME}" --generate-notes
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Build output
/build/
build-*/
cmake-build-*/
out/

# CMake
CMakeCache.txt
CMakeFiles/
CMakeUserPresets.json
_deps/
*.cmake.user

# vcpkg
vcpkg_installed/

# Editor / OS
.vscode/
.idea/
.cache/
compile_commands.json
.DS_Store

# Workspace
.context/
51 changes: 51 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Decart C++ SDK β€” Coding Agent Guidelines

## Build / test commands

- `cmake --preset release` β€” configure (downloads LiveKit, fetches IXWebSocket/json)
- `cmake --build --preset release` β€” build library, examples, tests
- `ctest --preset release` β€” run unit tests (or run `build/release/tests/decart_tests`)
- `./scripts/format.sh` / `clang-format -i` β€” format (`.clang-format`, 110 cols, Google base)
- Auth/tokens-only build (no LiveKit): `cmake -B build -S . -DDECART_BUILD_REALTIME=OFF`
(compiles out `Client::realtime()` via the `DECART_NO_REALTIME` interface define)

## Architecture

A realtime session = **WebSocket signaling** (control) + **LiveKit/WebRTC** (media).

- `include/decart/` β€” public API. `client.h` (Client/ClientOptions), `models.h`
(model registry), `tokens.h` (auth), `errors.h`, `logging.h`,
`realtime/{realtime,session,types}.h`.
- `src/` β€” implementation.
- `client.cpp`, `models.cpp`, `tokens.cpp`, `logging.cpp`, `errors.cpp`
- `detail/` β€” internal helpers: `http_client` (IXWebSocket HTTP), `signaling_channel`
(WebSocket + ack/event dispatch), `base64`, `url`, `user_agent`, `client_config`, `log`.
- `realtime/` β€” `messages` (pure JSON codec, unit-tested), `realtime` (RealtimeClient
forwarders), `session` (the orchestration + LiveKit `RoomDelegate` + frame pump).
- `tests/` β€” doctest unit tests for the dependency-light core (models, message codec,
base64, enums). Keep new pure logic testable here.

## Conventions

- **C++17**. PascalCase types, camelCase methods, `decart::` namespace, internal
helpers under `decart::detail`. This matches the LiveKit C++ SDK ergonomics, since
callers mix `decart::` and `livekit::` types in the same code.
- Public headers stay light: forward-declare `livekit::VideoSource`/`VideoFrame`
rather than including LiveKit; never expose `nlohmann::json` in the public API.
- Errors: throw `decart::Exception{Error{code, message}}` for synchronous failures;
deliver async session errors via the `onError` callback. Codes mirror the other SDKs.
- The signaling protocol's wire shapes live in `src/realtime/messages.*` β€” keep them
byte-compatible with the other SDKs (`type`, `prompt`, `enhance_prompt`,
`image_data`/`image_ref`, `livekit_join`, `livekit_room_info`, acks, etc.).

## Gotchas

- The released LiveKit `RoomOptions` is narrower than `main` β€” validate API usage
against the **release** headers (downloaded to `build/*/_deps/livekit-sdk/...`),
not the upstream `main` branch.
- `VideoCodec` is forward-declared only in LiveKit's public headers, so the publish
codec cannot be set from consumer code β€” leave it at the default.
- Never call `room.disconnect()` (or `session->disconnect()`) from inside a
delegate/session callback β€” it deadlocks the LiveKit event thread.
- The LiveKit FFI shared library must sit next to the executable; use
`decart_copy_livekit_runtime(target)` for any binary that links `decart`.
Loading
Loading