Skip to content
Open
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
4 changes: 4 additions & 0 deletions .github/workflows/carl-install-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ jobs:
# THIS PR (not main). Falls back to manual workflow_dispatch input
# when not in a PR context.
CARL_INSTALL_REF: ${{ github.event.pull_request.head.sha || inputs.install_ref || github.sha }}
# Canary is the integration sync point. A canary PR/push must test
# the image set that agents are actually validating from canary,
# not stale :latest images from main.
CONTINUUM_IMAGE_TAG: ${{ (github.event.pull_request.base.ref == 'canary' || github.ref_name == 'canary') && 'canary' || 'latest' }}
# 25-min cap on the docker-only install. Hybrid (Mac source-build)
# path would exceed this — by design, that's the gate firing on
# the README/install mismatch.
Expand Down
14 changes: 13 additions & 1 deletion docker-compose.mac.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@
# or localhost (since it's also on the host).
# Support services → IN CONTAINERS (this file):
# postgres, node-server, widget-server,
# livekit-bridge, model-init.
# model-init.
# livekit-bridge → NATIVE process on host. It exposes a Unix
# socket consumed by native continuum-core, and
# Docker Desktop bind mounts cannot host Unix
# socket creation reliably (Linux errno 95).
#
# This override sets continuum-core's `deploy.replicas: 0` so `docker compose
# up` on Mac brings up everything EXCEPT continuum-core. The install.sh
Expand Down Expand Up @@ -56,6 +60,14 @@ services:
deploy:
replicas: 0

# livekit-bridge also stays native on Mac. Containerizing it requires
# binding /root/.continuum/sockets/livekit-bridge.sock on a host-mounted
# ~/.continuum/sockets directory; Docker Desktop returns ENOTSUP for that
# socket bind. npm start launches the native binary via workers-config.json.
livekit-bridge:
deploy:
replicas: 0

# node-server runs in Docker on Mac (containerized per Option B).
# It needs to reach the NATIVE continuum-core-server on the host.
# Unix sockets don't traverse Docker Desktop's VM boundary on Mac, so
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ services:
# --no-default-features excludes livekit-webrtc (handled by livekit-bridge).
# load-dynamic-ort loads ONNX Runtime as shared lib (runtime discovery).
GPU_FEATURES: "--no-default-features --features load-dynamic-ort"
image: ghcr.io/cambriantech/continuum-core:${CONTINUUM_IMAGE_TAG:-latest}
image: ghcr.io/cambriantech/continuum-core:${CONTINUUM_CORE_IMAGE_TAG:-latest}
restart: unless-stopped
# Sized for mission: Qwen 4-8B Q4 + KV cache for 5 personas + embeddings
# + Bevy render + vision + audio. Auto-calculated by install.sh from host
Expand Down Expand Up @@ -138,7 +138,7 @@ services:
build:
context: ./src/workers
dockerfile: ../../docker/livekit-bridge.Dockerfile
image: ghcr.io/cambriantech/continuum-livekit-bridge:${CONTINUUM_IMAGE_TAG:-latest}
image: ghcr.io/cambriantech/continuum-livekit-bridge:${CONTINUUM_LIVEKIT_BRIDGE_IMAGE_TAG:-latest}
restart: unless-stopped
# WebRTC encode/decode buffers + multi-stream. Scales with host RAM —
# install.sh sets LIVEKIT_BRIDGE_MEM to max(2, host_gb/8). Default 2g
Expand Down
104 changes: 101 additions & 3 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -850,9 +850,16 @@ fi

# ── 7. Pull support-service images ─────────────────────────
PHASE="pull images"
# Image tag resolution: compose files honor ${CONTINUUM_IMAGE_TAG:-latest}.
# Image tag resolution: compose files honor ${CONTINUUM_IMAGE_TAG:-latest}
# for the light TypeScript/downloader services. Heavy Rust services are
# deliberately split: continuum-core honors ${CONTINUUM_CORE_IMAGE_TAG:-latest}
# and livekit-bridge honors ${CONTINUUM_LIVEKIT_BRIDGE_IMAGE_TAG:-latest}.
# Canary publishes light images more frequently than the heavy Rust images;
# splitting the tags lets canary installs test fresh node/widget code without
# falling back to multi-hour local Rust image builds.
#
# Main-branch installs (Carl's default) use :latest. Reviewers validating
# a PR before merge can pin the PR's staged image set:
# a PR before merge can pin the PR's staged light-image set:
# CONTINUUM_IMAGE_TAG=pr-891 curl -fsSL install.sh | bash
# CI tags every PR build with pr-<number> (see .github/workflows/docker-images.yml).
# Merging to main promotes that image set to :latest, so main and :latest
Expand All @@ -861,7 +868,7 @@ PHASE="pull images"
# On Mac: `continuum-core` is not pulled (replicas=0 in docker-compose.mac.yml);
# only support services (postgres, node-server, widget-server, livekit-bridge,
# model-init) are pulled. continuum-core runs natively from `npm start` below.
info "Pulling container images (tag: ${CONTINUUM_IMAGE_TAG:-latest})..."
info "Pulling container images (light=${CONTINUUM_IMAGE_TAG:-latest}, core=${CONTINUUM_CORE_IMAGE_TAG:-latest}, livekit-bridge=${CONTINUUM_LIVEKIT_BRIDGE_IMAGE_TAG:-latest})..."
$CONTAINER_CMD compose $COMPOSE_FILES $COMPOSE_ARGS pull 2>/dev/null || warn "Some images not published yet — will build locally"

# ── 8. Start support services ──────────────────────────────
Expand All @@ -879,6 +886,36 @@ fi
info "Starting support services..."
$CONTAINER_CMD compose $COMPOSE_FILES $COMPOSE_ARGS up -d

# Some published continuum-core images may predate the in-binary socket chmod
# fix. On Linux installs the host-side jtag CLI connects to the bind-mounted
# core socket, so make the install path resilient until every architecture's
# heavy core image has been refreshed.
fix_core_socket_permissions() {
local socket_dir="$CONTINUUM_DATA/sockets"
local core_socket="$socket_dir/continuum-core.sock"

[ -d "$socket_dir" ] || return 1

chmod 755 "$socket_dir" 2>/dev/null \
|| sudo -n chmod 755 "$socket_dir" 2>/dev/null \
|| warn "Could not chmod $socket_dir; host jtag may get EACCES"

[ -S "$core_socket" ] || return 1

chmod 666 "$core_socket" 2>/dev/null \
|| sudo -n chmod 666 "$core_socket" 2>/dev/null \
|| warn "Could not chmod $core_socket; host jtag may get EACCES"
}

if [[ "$OS" != "Darwin" ]]; then
for _ in $(seq 1 60); do
if fix_core_socket_permissions; then
break
fi
sleep 1
done
fi

# ── 8b. Start continuum-core natively on Mac ───────────────
# Mac runs continuum-core as a native host process so it can link Metal
# directly. `npm start` drives the full build (cargo build --release
Expand Down Expand Up @@ -942,11 +979,72 @@ for i in $(seq 1 "$HEALTH_TIMEOUT_SEC"); do
|| curl -sfk --max-time 2 https://localhost:9003/health >/dev/null 2>&1; then
HEALTH_OK=1
ok "widget-server healthy after ${i}s"
if [[ "$OS" != "Darwin" ]]; then
fix_core_socket_permissions || true
fi
break
fi
sleep 1
done

# ── 8c. Wait for first-chat seed readiness ─────────────────
PHASE="chat seed readiness"
wait_for_general_room() {
local jtag_bin=""
local out=""
local cand

for cand in \
"$INSTALL_DIR/src/jtag" \
"$HOME/.local/bin/jtag" \
"$(command -v jtag 2>/dev/null)"; do
if [ -n "$cand" ] && [ -x "$cand" ]; then
jtag_bin="$cand"
break
fi
done

if [ -z "$jtag_bin" ]; then
warn "jtag CLI not found; cannot verify seeded #general room before browser open"
return 1
fi

# Probe the same routing path first chat uses. Raw data/list can prove a
# room row exists, but chat/send resolves through RoutingService; the user
# is not ready until that resolver accepts "general".
out=$("$jtag_bin" collaboration/chat/export --room=general --limit=1 2>&1 || true)
if echo "$out" | grep -Eq '"success"[[:space:]]*:[[:space:]]*true'; then
return 0
fi

return 1
}

if [ "$HEALTH_OK" -eq 1 ]; then
info "Waiting for chat seed readiness (timeout ${CHAT_READY_TIMEOUT_SEC:=120}s)..."
CHAT_READY_OK=0
for i in $(seq 1 "$CHAT_READY_TIMEOUT_SEC"); do
if wait_for_general_room; then
CHAT_READY_OK=1
ok "chat seed ready after ${i}s (#general exists)"
break
fi
sleep 1
done

if [ "$CHAT_READY_OK" -ne 1 ]; then
warn "Chat seed did not become ready after ${CHAT_READY_TIMEOUT_SEC}s — #general is not resolvable by chat commands."
warn " The UI may load, but first chat will fail until auto-seed catches up."
echo ""
echo " Diagnose:"
echo " $CONTAINER_CMD compose $COMPOSE_FILES logs --tail=200 node-server continuum-core"
echo " $INSTALL_DIR/src/jtag data/list --collection=rooms --filter='{\"uniqueId\":\"general\"}' --limit=1"
echo " $INSTALL_DIR/src/jtag collaboration/chat/export --room=general --limit=1"
echo ""
fail "Chat seed readiness failed"
fi
fi

# ── 9. Determine URL + open browser (only if healthy) ──────
PHASE="open browser"
if [ -n "$TS_HOSTNAME" ] && [ -f "$CONTINUUM_DATA/$TS_HOSTNAME.crt" ]; then
Expand Down
9 changes: 9 additions & 0 deletions scripts/ci/carl-install-smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,15 @@ if [ $SEND_RC -ne 0 ]; then
echo "❌ chat probe: chat/send command FAILED (exit $SEND_RC)"
echo " Output:"
echo "$SEND_OUT" | head -10 | sed 's/^/ /'
{
echo ""
echo "━━ diagnostics after chat/send failure ━━"
echo "$ $JTAG_BIN data/list --collection=rooms --filter='{\"uniqueId\":\"general\"}' --limit=3"
"$JTAG_BIN" data/list --collection=rooms --filter='{"uniqueId":"general"}' --limit=3 2>&1 || true
echo ""
echo "$ $JTAG_BIN collaboration/chat/export --room=general --limit=1"
"$JTAG_BIN" collaboration/chat/export --room=general --limit=1 2>&1 || true
} | sed 's/^/ /' >> "$CHAT_LOG"
exit 4
fi

Expand Down
2 changes: 1 addition & 1 deletion src/scripts/parallel-start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ build_pkg() {
fi
}

for pkg in archive-worker jtag-mcp; do
for pkg in archive-worker jtag-mcp livekit-bridge; do
build_pkg "$pkg"
done
# continuum-core: all GPU features (metal+accelerate on macOS, cuda on Linux)
Expand Down
9 changes: 9 additions & 0 deletions src/workers/workers-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@
"args": [],
"description": "Unified Rust runtime: Voice, Data, Embedding, Search, Logger modules",
"enabled": true
},
{
"name": "livekit-bridge",
"binary": "workers/target/release/livekit-bridge",
"socket": ".continuum/sockets/livekit-bridge.sock",
"args": [],
"description": "LiveKit WebRTC bridge for native continuum-core",
"enabled": true,
"memoryLimit": "2G"
}
],
"sharedSockets": [
Expand Down
Loading