1- .PHONY : help install format format-check lint check type-check test test-unit test-docker clean build
1+ .PHONY : help install format format-check lint lint-fix check type-check test test-unit test-docker clean build \
2+ link-rtc link-rtc-local link-rtc-version unlink-rtc status doctor
23
34# Colors for output
45CYAN := \033[36m
@@ -8,12 +9,31 @@ RED := \033[31m
89RESET := \033[0m
910BOLD := \033[1m
1011
12+ # Paths (computed as absolute paths)
13+ MAKEFILE_DIR := $(shell pwd)
14+ AGENTS_PROJECT := $(MAKEFILE_DIR ) /livekit-agents
15+ PYTHON_RTC := $(MAKEFILE_DIR ) /../python-sdks/livekit-rtc
16+ RUST_SUBMODULE := $(MAKEFILE_DIR ) /../python-sdks/livekit-rtc/rust-sdks
17+ PACKAGE_NAME := livekit
18+
19+ # Platform and architecture auto-detection
20+ ARCH := $(shell uname -m)
21+ OS := $(shell uname -s | tr A-Z a-z)
22+
1123# Default target
1224.DEFAULT_GOAL := help
1325
1426help : # # Show this help message
1527 @echo " $( BOLD) $( CYAN) Available targets:$( RESET) "
16- @grep -E ' ^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST ) | sort | awk ' BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}'
28+ @echo " "
29+ @echo " $( BOLD) Development Workflows:$( RESET) "
30+ @grep -E ' ^(link-rtc|link-rtc-local|link-rtc-version|unlink-rtc|status|doctor):.*?## .*$$' $(MAKEFILE_LIST ) | awk ' BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}'
31+ @echo " "
32+ @echo " $( BOLD) Code Quality:$( RESET) "
33+ @grep -E ' ^(format|format-check|lint|lint-fix|type-check|check):.*?## .*$$' $(MAKEFILE_LIST ) | awk ' BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}'
34+ @echo " "
35+ @echo " $( BOLD) Other:$( RESET) "
36+ @grep -E ' ^(install|clean|build):.*?## .*$$' $(MAKEFILE_LIST ) | awk ' BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}'
1737
1838install : # # Install all dependencies with dev extras
1939 @echo " $( BOLD) $( CYAN) Installing dependencies...$( RESET) "
@@ -97,4 +117,246 @@ type-check: ## Run mypy type checker
97117 fi
98118
99119check : format-check lint type-check # # Run all checks (format, lint, type-check)
100- @echo " $( BOLD) $( GREEN) ✓ All checks passed!$( RESET) "
120+ @echo " $( BOLD) $( GREEN) ✓ All checks passed!$( RESET) "
121+
122+ # ============================================
123+ # Development Workflows
124+ # ============================================
125+
126+ link-rtc : # # Link to local python-rtc (default FFI version)
127+ @echo " $( BOLD) $( CYAN) 🐍 Linking local python-rtc with default FFI version...$( RESET) "
128+ @set -e; \
129+ DETECTED_ARCH=" $( ARCH) " ; \
130+ DETECTED_OS=" $( OS) " ; \
131+ if [ " $$ DETECTED_ARCH" = " aarch64" ]; then \
132+ PLATFORM_ARCH=" arm64" ; \
133+ else \
134+ PLATFORM_ARCH=" $$ DETECTED_ARCH" ; \
135+ fi ; \
136+ if [ " $$ DETECTED_OS" = " darwin" ]; then \
137+ PLATFORM_OS=" macos" ; \
138+ else \
139+ PLATFORM_OS=" $$ DETECTED_OS" ; \
140+ fi ; \
141+ echo " $( CYAN) 📦 Downloading FFI artifacts for $$ PLATFORM_OS-$$ PLATFORM_ARCH...$( RESET) " ; \
142+ cd $(PYTHON_RTC ) && python rust-sdks/download_ffi.py --platform " $$ PLATFORM_OS" --arch " $$ PLATFORM_ARCH" --output livekit/rtc/resources; \
143+ echo " $( CYAN) 🔗 Adding local python-rtc to agents...$( RESET) " ; \
144+ cd $(AGENTS_PROJECT ) && uv add --editable " ../../python-sdks/livekit-rtc" && uv sync; \
145+ rm -f $(AGENTS_PROJECT ) /.env; \
146+ echo " $( BOLD) $( GREEN) ✅ Linked to local python-rtc (with default FFI version)$( RESET) "
147+
148+ link-rtc-local : # # Build and link local rust SDK from source
149+ @echo " $( BOLD) $( CYAN) 🦀 Building and linking local rust SDK...$( RESET) "
150+ @set -e; \
151+ echo " $( CYAN) 🦀 Building livekit-ffi...$( RESET) " ; \
152+ cd $(RUST_SUBMODULE ) && cargo build --release -p livekit-ffi; \
153+ echo " $( CYAN) 📝 Generating protobuf FFI protocol...$( RESET) " ; \
154+ cd $(PYTHON_RTC ) && ./generate_proto.sh; \
155+ RUST_LIB_DIR=" $$ (cd $( RUST_SUBMODULE) && pwd)/target/release" ; \
156+ if [ " $( OS) " = " darwin" ]; then \
157+ RUST_LIB_PATH=" $$ RUST_LIB_DIR/liblivekit_ffi.dylib" ; \
158+ elif [ " $( OS) " = " linux" ]; then \
159+ RUST_LIB_PATH=" $$ RUST_LIB_DIR/liblivekit_ffi.so" ; \
160+ else \
161+ RUST_LIB_PATH=" $$ RUST_LIB_DIR/livekit_ffi.dll" ; \
162+ fi ; \
163+ echo " $( CYAN) LIVEKIT_LIB_PATH=$$ RUST_LIB_PATH$( RESET) " ; \
164+ echo " $( CYAN) 🔗 Adding local python-rtc to agents...$( RESET) " ; \
165+ cd $(AGENTS_PROJECT ) && uv add --editable " ../../python-sdks/livekit-rtc" && uv sync; \
166+ echo " LIVEKIT_LIB_PATH=$$ RUST_LIB_PATH" > $(AGENTS_PROJECT ) /.env; \
167+ echo " $( BOLD) $( GREEN) ✅ Linked to local rust-sdk + python-rtc$( RESET) " ; \
168+ echo " " ; \
169+ echo " $( BOLD) $( YELLOW) 📋 To use the local rust lib in your terminal, run:$( RESET) " ; \
170+ echo " $( BOLD) export LIVEKIT_LIB_PATH=$$ RUST_LIB_PATH$( RESET) "
171+
172+ link-rtc-version : # # Install specific livekit version from PyPI (e.g., make link-rtc-version VERSION=0.18.0)
173+ ifndef VERSION
174+ @echo "$(BOLD)$(RED)Error: VERSION not specified. Use: make link-rtc-version VERSION=0.18.0$(RESET)"
175+ @exit 1
176+ endif
177+ @echo "$(BOLD)$(CYAN)📦 Installing livekit version $(VERSION)...$(RESET)"
178+ @set -e; \
179+ if grep -q "^livekit = { path = " pyproject.toml 2>/dev/null; then \
180+ echo "$(CYAN) Removing workspace root livekit source override...$(RESET)"; \
181+ sed -i.bak '/^livekit = { path = /d' pyproject.toml && rm -f pyproject.toml.bak; \
182+ fi; \
183+ cd $(AGENTS_PROJECT); \
184+ if grep -q "\[tool.uv.sources\]" pyproject.toml && grep -q "^livekit = " pyproject.toml; then \
185+ echo "$(CYAN) Removing [tool.uv.sources] override...$(RESET)"; \
186+ sed -i.bak '/^livekit = /d' pyproject.toml && rm -f pyproject.toml.bak; \
187+ fi; \
188+ uv remove $(PACKAGE_NAME) 2>/dev/null || true; \
189+ uv add "$(PACKAGE_NAME)==$(VERSION)" && uv sync; \
190+ rm -f .env; \
191+ echo "$(BOLD)$(GREEN)✅ Linked to livekit $(VERSION)$(RESET)"
192+
193+ unlink-rtc : # # Unlink local and restore PyPI version
194+ @echo " $( BOLD) $( CYAN) 🔓 Unlinking local python-rtc...$( RESET) "
195+ @set -e; \
196+ if grep -q " ^livekit = { path = " pyproject.toml 2> /dev/null; then \
197+ echo " $( CYAN) Removing workspace root livekit source override...$( RESET) " ; \
198+ sed -i.bak ' /^livekit = { path = /d' pyproject.toml && rm -f pyproject.toml.bak; \
199+ fi ; \
200+ cd $(AGENTS_PROJECT ) ; \
201+ if grep -q " \[tool.uv.sources\]" pyproject.toml; then \
202+ echo " $( CYAN) Removing [tool.uv.sources] override...$( RESET) " ; \
203+ sed -i.bak ' /\[tool.uv.sources\]/,/^livekit = /d' pyproject.toml && rm -f pyproject.toml.bak; \
204+ fi ; \
205+ uv remove --dev $(PACKAGE_NAME ) 2> /dev/null || true ; \
206+ uv add --upgrade-package $(PACKAGE_NAME ) $(PACKAGE_NAME ) && uv sync; \
207+ rm -f .env; \
208+ echo " $( BOLD) $( GREEN) ✅ Restored PyPI version$( RESET) "
209+
210+ status : # # Show current linking status
211+ @echo " $( BOLD) $( CYAN) 📍 Current status:$( RESET) "
212+ @echo " "
213+ @set -e; \
214+ RUST_SUBMODULE_DIR=" $$ (cd $( RUST_SUBMODULE) 2>/dev/null && pwd || echo " " )" ; \
215+ cd $(AGENTS_PROJECT ) ; \
216+ SHOW_OUTPUT=$$(uv pip show livekit 2>/dev/null || echo "" ) ; \
217+ IS_LOCAL_EDITABLE=false; \
218+ if [ -z " $$ SHOW_OUTPUT" ]; then \
219+ echo " livekit: NOT INSTALLED" ; \
220+ elif echo " $$ SHOW_OUTPUT" | grep -q " Editable project location:" ; then \
221+ IS_LOCAL_EDITABLE=true; \
222+ VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}' ) ; \
223+ LOCATION=$$(echo "$$SHOW_OUTPUT" | grep "Editable project location:" | cut -d' ' -f4- ) ; \
224+ echo " livekit: LOCAL (editable) v$$ VERSION" ; \
225+ echo " path: $$ LOCATION" ; \
226+ else \
227+ VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}' ) ; \
228+ echo " livekit: PyPI (v$$ VERSION)" ; \
229+ fi ; \
230+ echo " " ; \
231+ if [ -f .env ] && grep -q " LIVEKIT_LIB_PATH" .env; then \
232+ SUBMODULE_COMMIT=$$([ -n "$$RUST_SUBMODULE_DIR" ] && cd "$$RUST_SUBMODULE_DIR" 2>/dev/null && git rev-parse --short HEAD || echo 'unknown' ) ; \
233+ echo " FFI: LOCAL BUILD (rust-sdks @ $$ SUBMODULE_COMMIT)" ; \
234+ elif [ " $$ IS_LOCAL_EDITABLE" = " true" ]; then \
235+ FFI_PATH=" $$ (cd $( PYTHON_RTC) 2>/dev/null && pwd || echo " " )/livekit/rtc/resources" ; \
236+ if [ -d " $$ FFI_PATH" ] && { [ -f " $$ FFI_PATH/liblivekit_ffi.dylib" ] || [ -f " $$ FFI_PATH/liblivekit_ffi.so" ] || [ -f " $$ FFI_PATH/livekit_ffi.dll" ]; }; then \
237+ CARGO_TOML_PATH=" $$ RUST_SUBMODULE_DIR/livekit-ffi/Cargo.toml" ; \
238+ if [ -f " $$ CARGO_TOML_PATH" ]; then \
239+ FFI_VERSION=$$(grep '^version = ' "$$CARGO_TOML_PATH" | head -1 | sed 's/.*"\(.*\ ) " .*/\1/'); \
240+ echo " FFI: PRE-BUILT ARTIFACTS (v$$ FFI_VERSION)" ; \
241+ else \
242+ echo " FFI: PRE-BUILT ARTIFACTS" ; \
243+ fi ; \
244+ else \
245+ echo " FFI: NOT AVAILABLE" ; \
246+ fi ; \
247+ else \
248+ echo " FFI: BUNDLED (PyPI package)" ; \
249+ fi
250+
251+ doctor : # # Check development environment health
252+ @echo " $( BOLD) $( CYAN) 🏥 Running diagnostics...$( RESET) "
253+ @echo " "
254+ @ISSUES=0; \
255+ echo " $( BOLD) 📦 Required Tools:$( RESET) " ; \
256+ if command -v uv & > /dev/null; then \
257+ UV_VERSION=$$(uv --version 2>&1 | head -1 ) ; \
258+ echo " ✓ uv: $$ UV_VERSION" ; \
259+ else \
260+ echo " ✗ uv: NOT FOUND" ; \
261+ ISSUES=$$((ISSUES + 1 ) ); \
262+ fi ; \
263+ if command -v python & > /dev/null; then \
264+ PYTHON_VERSION=$$(python --version 2>&1 ) ; \
265+ echo " ✓ python: $$ PYTHON_VERSION" ; \
266+ else \
267+ echo " ✗ python: NOT FOUND" ; \
268+ ISSUES=$$((ISSUES + 1 ) ); \
269+ fi ; \
270+ if command -v cargo & > /dev/null; then \
271+ CARGO_VERSION=$$(cargo --version 2>&1 ) ; \
272+ echo " ✓ cargo: $$ CARGO_VERSION" ; \
273+ else \
274+ echo " ⚠ cargo: NOT FOUND (required for 'make link-rtc-local')" ; \
275+ fi ; \
276+ if command -v git & > /dev/null; then \
277+ GIT_VERSION=$$(git --version 2>&1 ) ; \
278+ echo " ✓ git: $$ GIT_VERSION" ; \
279+ else \
280+ echo " ✗ git: NOT FOUND" ; \
281+ ISSUES=$$((ISSUES + 1 ) ); \
282+ fi ; \
283+ echo " " ; \
284+ echo " $( BOLD) 📂 Repository Structure:$( RESET) " ; \
285+ if [ -d " $( PYTHON_RTC) " ]; then \
286+ echo " ✓ python-rtc: $$ (cd $( PYTHON_RTC) && pwd)" ; \
287+ PYTHON_RTC_BRANCH=$$(cd $(PYTHON_RTC ) && git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "" ) ; \
288+ if [ -n " $$ PYTHON_RTC_BRANCH" ]; then \
289+ PYTHON_RTC_COMMIT=$$(cd $(PYTHON_RTC ) && git rev-parse --short HEAD 2>/dev/null || echo "unknown" ) ; \
290+ echo " Branch: $$ PYTHON_RTC_BRANCH @ $$ PYTHON_RTC_COMMIT" ; \
291+ fi ; \
292+ else \
293+ echo " ✗ python-rtc: NOT FOUND at $( PYTHON_RTC) " ; \
294+ ISSUES=$$((ISSUES + 1 ) ); \
295+ fi ; \
296+ if [ -d " $( RUST_SUBMODULE) " ]; then \
297+ echo " ✓ rust-submodule: $$ (cd $( RUST_SUBMODULE) && pwd)" ; \
298+ if [ -e " $( RUST_SUBMODULE) /.git" ]; then \
299+ RUST_BRANCH=$$(cd $(RUST_SUBMODULE ) && git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown" ) ; \
300+ RUST_COMMIT=$$(cd $(RUST_SUBMODULE ) && git rev-parse --short HEAD 2>/dev/null || echo "unknown" ) ; \
301+ RUST_TAG=$$(cd $(RUST_SUBMODULE ) && git describe --exact-match --tags 2>/dev/null || echo "" ) ; \
302+ if [ -n " $$ RUST_TAG" ]; then \
303+ echo " Branch: $$ RUST_BRANCH @ $$ RUST_COMMIT (tag: $$ RUST_TAG)" ; \
304+ else \
305+ echo " Branch: $$ RUST_BRANCH @ $$ RUST_COMMIT" ; \
306+ fi ; \
307+ else \
308+ echo " ⚠ Not a git repository" ; \
309+ fi ; \
310+ else \
311+ echo " ✗ rust-submodule: NOT FOUND at $( RUST_SUBMODULE) " ; \
312+ ISSUES=$$((ISSUES + 1 ) ); \
313+ fi ; \
314+ if [ -d " $( AGENTS_PROJECT) " ]; then \
315+ AGENTS_ABS_PATH=$$(cd $(AGENTS_PROJECT ) && pwd ) ; \
316+ echo " ✓ agents-project: $$ AGENTS_ABS_PATH" ; \
317+ AGENTS_REPO_ROOT=$$(cd $(MAKEFILE_DIR ) && git rev-parse --show-toplevel 2>/dev/null || echo "" ) ; \
318+ if [ -n " $$ AGENTS_REPO_ROOT" ]; then \
319+ AGENTS_BRANCH=$$(cd $(MAKEFILE_DIR ) && git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown" ) ; \
320+ AGENTS_COMMIT=$$(cd $(MAKEFILE_DIR ) && git rev-parse --short HEAD 2>/dev/null || echo "unknown" ) ; \
321+ echo " Branch: $$ AGENTS_BRANCH @ $$ AGENTS_COMMIT" ; \
322+ fi ; \
323+ else \
324+ echo " ✗ agents-project: NOT FOUND at $( AGENTS_PROJECT) " ; \
325+ ISSUES=$$((ISSUES + 1 ) ); \
326+ fi ; \
327+ echo " " ; \
328+ echo " $( BOLD) 🔍 Current Configuration:$( RESET) " ; \
329+ if [ -d " .venv" ]; then \
330+ echo " ✓ Virtual environment: .venv exists" ; \
331+ else \
332+ echo " ⚠ Virtual environment: .venv not found (run 'make install')" ; \
333+ fi ; \
334+ cd $(AGENTS_PROJECT ) ; \
335+ SHOW_OUTPUT=$$(uv pip show livekit 2>/dev/null || echo "" ) ; \
336+ if [ -z " $$ SHOW_OUTPUT" ]; then \
337+ echo " ✗ livekit: NOT INSTALLED" ; \
338+ echo " Run 'make link-rtc' to set up" ; \
339+ ISSUES=$$((ISSUES + 1 ) ); \
340+ elif echo " $$ SHOW_OUTPUT" | grep -q " Editable project location:" ; then \
341+ VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}' ) ; \
342+ echo " ✓ livekit: LOCAL (editable) v$$ VERSION" ; \
343+ else \
344+ VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}' ) ; \
345+ echo " ✓ livekit: PyPI v$$ VERSION" ; \
346+ fi ; \
347+ if [ -f .env ] && grep -q " LIVEKIT_LIB_PATH" .env; then \
348+ LIVEKIT_LIB_PATH=$$(grep "LIVEKIT_LIB_PATH" .env | cut -d'=' -f2 ) ; \
349+ if [ -d " $$ LIVEKIT_LIB_PATH" ]; then \
350+ echo " ✓ FFI: Local build at $$ LIVEKIT_LIB_PATH" ; \
351+ else \
352+ echo " ✗ FFI: Local build path not found: $$ LIVEKIT_LIB_PATH" ; \
353+ ISSUES=$$((ISSUES + 1 ) ); \
354+ fi ; \
355+ fi ; \
356+ echo " " ; \
357+ if [ $$ ISSUES -eq 0 ]; then \
358+ echo " $( BOLD) $( GREEN) ✅ All checks passed! Environment is healthy.$( RESET) " ; \
359+ else \
360+ echo " $( BOLD) $( RED) ⚠️ Found $$ ISSUES issue(s). Please fix the errors above.$( RESET) " ; \
361+ exit 1; \
362+ fi
0 commit comments