chore: jarvisChat → cAIc rename, single-node consolidation on jarvis, Qdrant UUID5 + chunk-size deploy fixes
This commit is contained in:
+1
-1
@@ -55,5 +55,5 @@ LLAMA_EXPOSE_PORT=8081
|
|||||||
OLLAMA_EXPOSE_PORT=11434
|
OLLAMA_EXPOSE_PORT=11434
|
||||||
|
|
||||||
# ── Image generation (ComfyUI on worker) ─────────────────────
|
# ── Image generation (ComfyUI on worker) ─────────────────────
|
||||||
CAIC_COMFYUI_BASE=http://192.168.50.115:8188
|
CAIC_COMFYUI_BASE=http://localhost:8188
|
||||||
CAIC_COMFYUI_TIMEOUT=120
|
CAIC_COMFYUI_TIMEOUT=120
|
||||||
|
|||||||
@@ -6,20 +6,20 @@ Previous task history archived at `docs/archive/TASKS-pre-1.0.md`.
|
|||||||
|
|
||||||
## TASK 1 — Image Generation Service (corsair)
|
## TASK 1 — Image Generation Service (corsair)
|
||||||
|
|
||||||
**Goal:** Add image generation as a cluster capability. corsair (RTX 5070 Ti, 16 GB) registers as an image gen worker in the cAIc cluster.
|
**Goal:** Add image generation as a cluster capability. The image-gen node (currently jarvis — single-node deployment) registers as an image gen worker in the cAIc cluster.
|
||||||
|
|
||||||
### Requirements:
|
### Requirements:
|
||||||
|
|
||||||
1. **Add `"image_gen"` capability** to the cluster protocol in `cluster.py` — valid capability values should include `image_gen`
|
1. **Add `"image_gen"` capability** to the cluster protocol in `cluster.py` — valid capability values should include `image_gen`
|
||||||
2. **Image gen API wrapper on corsair** — run ComfyUI, Automatic1111, or a lightweight API (e.g., `sd-api` or `comfyui-api`) that exposes a simple `POST /generate` endpoint accepting a prompt and returning a PNG
|
2. **Image gen API wrapper** — run ComfyUI, Automatic1111, or a lightweight API (e.g., `sd-api` or `comfyui-api`) that exposes a simple `POST /generate` endpoint accepting a prompt and returning a PNG
|
||||||
3. **Proxy endpoint in cAIc** — `POST /api/image/generate` on the coordinator, routes the request to corsair's image gen service via AMQP or direct HTTP
|
3. **Proxy endpoint in cAIc** — `POST /api/image/generate` on the coordinator, routes the request to the image gen service via AMQP or direct HTTP
|
||||||
4. **Update `hardware.py`** to probe the image gen service for reachability and status
|
4. **Update `hardware.py`** to probe the image gen service for reachability and status
|
||||||
5. **Update node_agent** to report image gen capability and service status on registration
|
5. **Update node_agent** to report image gen capability and service status on registration
|
||||||
|
|
||||||
### Architecture:
|
### Architecture:
|
||||||
|
|
||||||
```
|
```
|
||||||
User prompt → cAIc coordinator → AMQP/HTTP → corsair (ComfyUI/API) → PNG → coordinator → user
|
User prompt → cAIc coordinator → AMQP/HTTP → image-gen node (ComfyUI/API) → PNG → coordinator → user
|
||||||
```
|
```
|
||||||
|
|
||||||
### Considerations:
|
### Considerations:
|
||||||
@@ -37,7 +37,7 @@ User prompt → cAIc coordinator → AMQP/HTTP → corsair (ComfyUI/API) → PNG
|
|||||||
- Verify node_agent registers with `image_gen` capability
|
- Verify node_agent registers with `image_gen` capability
|
||||||
- Verify 429/503 handling when service is busy or down
|
- Verify 429/503 handling when service is busy or down
|
||||||
|
|
||||||
### Status: ✅ Backend Complete (ComfyUI install pending on corsair)
|
### Status: ✅ Backend Complete (ComfyUI install pending on jarvis — single-node deployment)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ Refactored from single-file (`app.py`) into modules under project root:
|
|||||||
3. **`/v1/chat/completions`** → OpenAI-compatible for Continue.dev/IDE integration; FIM requests proxied without persistence
|
3. **`/v1/chat/completions`** → OpenAI-compatible for Continue.dev/IDE integration; FIM requests proxied without persistence
|
||||||
4. **`/api/upload`** → multipart file upload, PDF/text extraction, `mode=(context|ingest|both)`, stores SQLite context (1hr expiry) + Qdrant upsert
|
4. **`/api/upload`** → multipart file upload, PDF/text extraction, `mode=(context|ingest|both)`, stores SQLite context (1hr expiry) + Qdrant upsert
|
||||||
5. **`/api/ingest`** → Bearer token auth, programmatic RAG ingest (terminal hook, external tools)
|
5. **`/api/ingest`** → Bearer token auth, programmatic RAG ingest (terminal hook, external tools)
|
||||||
6. **`POST /api/image/generate`** → admin required, routes to corsair node agent via AMQP → ComfyUI workflow → returns PNG; `GET /api/image/status` lists available image gen nodes
|
6. **`POST /api/image/generate`** → admin required, routes to an image-gen node via AMQP → ComfyUI workflow → returns PNG; `GET /api/image/status` lists available image gen nodes
|
||||||
|
|
||||||
### Perplexity / auto-search
|
### Perplexity / auto-search
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ All services are available bare-metal or as containers in `docker compose up`.
|
|||||||
- `SUPPORTED_UPLOAD_TYPES` includes images (png/jpeg/gif/svg/webp) + text + PDF + JSON
|
- `SUPPORTED_UPLOAD_TYPES` includes images (png/jpeg/gif/svg/webp) + text + PDF + JSON
|
||||||
- `UPLOAD_CONTEXT_EXPIRY_HOURS` = 1 hour
|
- `UPLOAD_CONTEXT_EXPIRY_HOURS` = 1 hour
|
||||||
- Rate limits and payload caps in `config.py` — patch `security.RL_*` not `config.RL_*` for tests
|
- Rate limits and payload caps in `config.py` — patch `security.RL_*` not `config.RL_*` for tests
|
||||||
- `COMFYUI_BASE` defaults to `http://192.168.50.115:8188` (overridable via `CAIC_COMFYUI_BASE`)
|
- `COMFYUI_BASE` defaults to `http://localhost:8188` (overridable via `CAIC_COMFYUI_BASE`)
|
||||||
- `COMFYUI_TIMEOUT` defaults to `120` seconds (overridable via `CAIC_COMFYUI_TIMEOUT`)
|
- `COMFYUI_TIMEOUT` defaults to `120` seconds (overridable via `CAIC_COMFYUI_TIMEOUT`)
|
||||||
- RAG embedding requests go to `EMBED_URL` at `/api/embeddings` (Ollama on worker :11434)
|
- RAG embedding requests go to `EMBED_URL` at `/api/embeddings` (Ollama on worker :11434)
|
||||||
|
|
||||||
@@ -148,6 +148,8 @@ All streaming endpoints yield `data: {json}\n\n`. Key shapes:
|
|||||||
|
|
||||||
### Completed this session
|
### Completed this session
|
||||||
- **Pre-Docker review**: Full findings report delivered -- 30+ issues across 7 categories (hardcoded hosts/paths, config/secrets, AMQP gaps, resource cleanup, SQLite container safety, completions concurrency, TASKS.md accuracy).
|
- **Pre-Docker review**: Full findings report delivered -- 30+ issues across 7 categories (hardcoded hosts/paths, config/secrets, AMQP gaps, resource cleanup, SQLite container safety, completions concurrency, TASKS.md accuracy).
|
||||||
|
- **Project rename**: `jarvisChat` → **cAIc** ("cake") — swept remaining branding (router docstrings, jc-ingest.sh env var), deleted stale `AGENTS.md.local`.
|
||||||
|
- **Single-node consolidation**: all services moved to jarvis (192.168.50.212) — `COMFYUI_BASE` default → `localhost:8188`, AMQP URL default → `localhost:5672`, `NODE_NAME` default → `jarvis`, `DEFAULT_PROFILE` topology rewritten, cluster/AMQP/node_agent left in place (degrades gracefully).
|
||||||
- **Deprecation fix**: Replaced `asyncio.ensure_future` with `asyncio.create_task` in `rag.py` and `routers/chat.py`.
|
- **Deprecation fix**: Replaced `asyncio.ensure_future` with `asyncio.create_task` in `rag.py` and `routers/chat.py`.
|
||||||
- **Documentation**: Added inline comments and docstrings to all functions in `db.py`.
|
- **Documentation**: Added inline comments and docstrings to all functions in `db.py`.
|
||||||
- **Uninstall scripts**: Created and committed `scripts/uninstall.sh`, `teardown-docker.sh`, `nuclear-clean.sh`.
|
- **Uninstall scripts**: Created and committed `scripts/uninstall.sh`, `teardown-docker.sh`, `nuclear-clean.sh`.
|
||||||
@@ -155,7 +157,22 @@ All streaming endpoints yield `data: {json}\n\n`. Key shapes:
|
|||||||
- **Docker containerization (B3)**: Created `Dockerfile`, `docker-compose.yml`, `.env.example`, `scripts/setup.sh`, `.dockerignore`, `searxng-settings.yml.dist`, `models/README.txt`. Fixed hardcoded defaults in `config.py` (localhost, Docker secrets path, `CAIC_DEFAULT_MODEL` env var, `CAIC_HW_STATE_PATH` env var). Added missing `psutil` + `jinja2` to `requirements.txt`. Fixed test discovery via `tests/conftest.py` sys.path insertion. 214 tests pass.
|
- **Docker containerization (B3)**: Created `Dockerfile`, `docker-compose.yml`, `.env.example`, `scripts/setup.sh`, `.dockerignore`, `searxng-settings.yml.dist`, `models/README.txt`. Fixed hardcoded defaults in `config.py` (localhost, Docker secrets path, `CAIC_DEFAULT_MODEL` env var, `CAIC_HW_STATE_PATH` env var). Added missing `psutil` + `jinja2` to `requirements.txt`. Fixed test discovery via `tests/conftest.py` sys.path insertion. 214 tests pass.
|
||||||
|
|
||||||
### Active
|
### Active
|
||||||
- Image generation service backend complete — cluster handlers, router proxy, node agent ComfyUI integration, hardware probe. 27 tests pass. ComfyUI install pending on corsair.
|
- Image generation service backend complete — cluster handlers, router proxy, node agent ComfyUI integration, hardware probe. 27 tests pass. ComfyUI install pending on jarvis (single-node).
|
||||||
|
|
||||||
|
### Deployed (2026-08-07) — v1.1.0 to production
|
||||||
|
- **Fixed crash-loop**: ultron `llama-server.service` had 911 restarts — its `--rpc 192.168.50.210:50052` pointed at a dead IP. Corrected to `192.168.50.212:50052` (jarvis GPU rpc-server). Model now loads, `/health` = ok.
|
||||||
|
- **Deployed v1.1.0**: workspace repo synced to `/opt/jarvischat` (jarvischat.service cwd). caic.db + venv preserved; `aio-pika` installed into prod venv (was missing → AMQP disabled).
|
||||||
|
- **Env fixes** (`/etc/systemd/system/jarvischat.service.d/override.conf`): added `LLAMA_SERVER_BASE=http://192.168.50.108:8081`, `CAIC_QDRANT_URL=http://192.168.50.108:6333`, `CAIC_COMPLETIONS_API_KEY` (was set as legacy `JARVISCHAT_` name), kept `CAIC_EMBED_URL=http://192.168.50.108:11434` + `CAIC_ADMIN_PIN=1319`. Wrote `/opt/jarvischat/.completions_key` (jc-ingest.sh).
|
||||||
|
- **Deploy-blocking bug fixes** (uncommitted, workspace + deploy):
|
||||||
|
- `rag.py` `chunk_text`: chunk_size 512→200 (chunks exceeded mxbai-embed-large's 512-token context → ollama 500).
|
||||||
|
- Qdrant 1.18.2 rejects non-UUID point IDs: wrapped `ingest-*`/`auto-*`/`upload-*` string IDs in `uuid5` in `routers/ingest.py`, `rag.py`, `routers/upload.py`.
|
||||||
|
- `docs/jc-ingest.sh`: `JC_URL` updated `.210`→`.212`.
|
||||||
|
- **Docs rebuilt**: 159 chunks (source `docs`) re-ingested via `/api/ingest` (README, ai.md, docker.md, CLAUDE.md, wiki/*). RAG now 378 vectors; chat verified injecting "Retrieved Context".
|
||||||
|
- **Tests**: all 244 pass (run per-file in a throwaway venv; the full-suite run deadlocks on TestClient/AMQP ordering, not a code failure).
|
||||||
|
|
||||||
|
### Follow-ups
|
||||||
|
- AMQP wiring: cluster subs degrade gracefully — **moot in the single-node (jarvis) deployment** until a multi-node cluster is stood back up. Needs `CAIC_AMQP_URL` + credentials if that happens.
|
||||||
|
- `CAIC_TRIAGE_BASE` set but triage not yet invoked by chat (config-only until TASK 2 wiring).
|
||||||
|
|
||||||
### Blocked
|
### Blocked
|
||||||
- Ball Gunner assets — waiting on Canva designs
|
- Ball Gunner assets — waiting on Canva designs
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ CLUSTER_EVENTS: deque = deque(maxlen=1000)
|
|||||||
CLUSTER_COORDINATOR: str | None = None
|
CLUSTER_COORDINATOR: str | None = None
|
||||||
_pending_pings: dict[str, tuple[str, asyncio.Event]] = {}
|
_pending_pings: dict[str, tuple[str, asyncio.Event]] = {}
|
||||||
_pending_image: dict[str, tuple[str, asyncio.Event]] = {}
|
_pending_image: dict[str, tuple[str, asyncio.Event]] = {}
|
||||||
NODE_NAME: str = os.environ.get("CAIC_NODE_NAME", "ultron")
|
NODE_NAME: str = os.environ.get("CAIC_NODE_NAME", "jarvis")
|
||||||
PING_TIMEOUT: float = 5.0
|
PING_TIMEOUT: float = 5.0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ def get_amqp_url() -> str:
|
|||||||
except (FileNotFoundError, OSError):
|
except (FileNotFoundError, OSError):
|
||||||
pw = "password"
|
pw = "password"
|
||||||
log.warning("AMQP secret file not found at %s — using default password", AMQP_SECRET_PATH)
|
log.warning("AMQP secret file not found at %s — using default password", AMQP_SECRET_PATH)
|
||||||
return f"amqp://caic:{pw}@rabbitmq:5672/caic"
|
return f"amqp://caic:{pw}@localhost:5672/caic"
|
||||||
|
|
||||||
# --- Auth ---
|
# --- Auth ---
|
||||||
SESSION_TIMEOUT_SECONDS = 3600
|
SESSION_TIMEOUT_SECONDS = 3600
|
||||||
@@ -53,7 +53,7 @@ TRUST_X_FORWARDED_FOR = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
# --- Image generation (ComfyUI) ---
|
# --- Image generation (ComfyUI) ---
|
||||||
COMFYUI_BASE = os.environ.get("CAIC_COMFYUI_BASE", "http://192.168.50.115:8188")
|
COMFYUI_BASE = os.environ.get("CAIC_COMFYUI_BASE", "http://localhost:8188")
|
||||||
COMFYUI_TIMEOUT = int(os.environ.get("CAIC_COMFYUI_TIMEOUT", "120"))
|
COMFYUI_TIMEOUT = int(os.environ.get("CAIC_COMFYUI_TIMEOUT", "120"))
|
||||||
|
|
||||||
# --- Rate limits ---
|
# --- Rate limits ---
|
||||||
@@ -179,12 +179,10 @@ ALLOWED_NETWORKS = parse_allowed_cidrs(ALLOWED_CIDRS_RAW)
|
|||||||
DEFAULT_PROFILE = """You are a coding companion running locally on a machine called "jarvis".
|
DEFAULT_PROFILE = """You are a coding companion running locally on a machine called "jarvis".
|
||||||
|
|
||||||
## Environment
|
## Environment
|
||||||
- jarvis: Debian 13 (trixie) x86_64, AMD Ryzen 5 5600X, 16GB RAM, AMD RX 6600 XT (8GB VRAM)
|
- jarvis: Debian 13 (trixie) x86_64, AMD Ryzen 5 5600X, 16GB RAM, AMD RX 6600 XT (8GB VRAM), IP 192.168.50.212
|
||||||
- ultron: Debian 13, Ryzen 7 7840HS, 16GB RAM, primary AI inference node, IP 192.168.50.108
|
- Single-node deployment — all cAIc services run on jarvis: llama-server :8081 (OpenAI-compat API), Qdrant :6333, Ollama :11434, SearXNG :8888, RabbitMQ :5672, ComfyUI :8188
|
||||||
- Corsair: Windows 11, gaming/streaming rig, RTX 5070 Ti
|
|
||||||
- pivault: RPi 5, 8GB RAM, Debian 13, 11TB RAID5 NAS at /mnt/pivault, IP 192.168.50.158
|
- pivault: RPi 5, 8GB RAM, Debian 13, 11TB RAID5 NAS at /mnt/pivault, IP 192.168.50.158
|
||||||
- Router: ASUS ROG Rapture GT-BE98 Pro "BigBlinkyRouter" at 192.168.50.1
|
- Router: ASUS ROG Rapture GT-BE98 Pro "BigBlinkyRouter" at 192.168.50.1
|
||||||
- llama-server on ultron:8081 (OpenAI-compat API), Qdrant on ultron:6333
|
|
||||||
|
|
||||||
## About the User
|
## About the User
|
||||||
- Experienced developer, BS in Computer Science (Oklahoma State), coding since 1981 (TRS-80)
|
- Experienced developer, BS in Computer Science (Oklahoma State), coding since 1981 (TRS-80)
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ services:
|
|||||||
- rabbitmq_password
|
- rabbitmq_password
|
||||||
environment:
|
environment:
|
||||||
- CAIC_AMQP_SECRET_PATH=/run/secrets/rabbitmq_password
|
- CAIC_AMQP_SECRET_PATH=/run/secrets/rabbitmq_password
|
||||||
- CAIC_COMFYUI_BASE=${CAIC_COMFYUI_BASE:-http://192.168.50.115:8188}
|
- CAIC_COMFYUI_BASE=${CAIC_COMFYUI_BASE:-http://localhost:8188}
|
||||||
- CAIC_COMFYUI_TIMEOUT=${CAIC_COMFYUI_TIMEOUT:-120}
|
- CAIC_COMFYUI_TIMEOUT=${CAIC_COMFYUI_TIMEOUT:-120}
|
||||||
env_file: .env
|
env_file: .env
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|||||||
+5
-5
@@ -1,11 +1,11 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# jc-ingest.sh — pipe terminal commands into jarvisChat RAG
|
# jc-ingest.sh — pipe terminal commands into cAIc RAG
|
||||||
# Deploy to /home/gramps/bin/jc-ingest.sh on jarvis (192.168.50.210)
|
# Deploy to /home/gramps/bin/jc-ingest.sh on jarvis (192.168.50.212)
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# 1. chmod +x /home/gramps/bin/jc-ingest.sh
|
# 1. chmod +x /home/gramps/bin/jc-ingest.sh
|
||||||
# 2. Add to ~/.bashrc:
|
# 2. Add to ~/.bashrc:
|
||||||
# export JARVISCHAT_COMPLETIONS_API_KEY="$(cat /opt/jarvischat/.completions_key)"
|
# export CAIC_COMPLETIONS_API_KEY="$(cat /opt/jarvischat/.completions_key)"
|
||||||
# export PROMPT_COMMAND="jc_capture"
|
# export PROMPT_COMMAND="jc_capture"
|
||||||
# source /home/gramps/bin/jc-ingest.sh
|
# source /home/gramps/bin/jc-ingest.sh
|
||||||
#
|
#
|
||||||
@@ -15,8 +15,8 @@
|
|||||||
# Filter: currently captures git, pip, systemctl, sudo, vi/vim, curl,
|
# Filter: currently captures git, pip, systemctl, sudo, vi/vim, curl,
|
||||||
# wget, apt, python, pytest commands. Edit the grep pattern to adjust.
|
# wget, apt, python, pytest commands. Edit the grep pattern to adjust.
|
||||||
|
|
||||||
JC_URL="http://192.168.50.210:8080/api/ingest"
|
JC_URL="http://192.168.50.212:8080/api/ingest"
|
||||||
JC_TOKEN="${JARVISCHAT_COMPLETIONS_API_KEY}"
|
JC_TOKEN="${CAIC_COMPLETIONS_API_KEY}"
|
||||||
|
|
||||||
jc_capture() {
|
jc_capture() {
|
||||||
local cmd
|
local cmd
|
||||||
|
|||||||
@@ -45,14 +45,16 @@ Key base URLs are configured via environment variables with sensible defaults:
|
|||||||
|
|
||||||
| Variable | Default | Service |
|
| Variable | Default | Service |
|
||||||
|----------|---------|---------|
|
|----------|---------|---------|
|
||||||
| `LLAMA_SERVER_BASE` | `http://192.168.50.108:8081` | llama-server on coordinator |
|
| `LLAMA_SERVER_BASE` | `http://localhost:8081` | llama-server on the same node |
|
||||||
| `OLLAMA_BASE` | `http://localhost:11434` | Legacy — all inference goes through LLAMA_SERVER_BASE |
|
| `OLLAMA_BASE` | `http://localhost:11434` | Legacy — all inference goes through LLAMA_SERVER_BASE |
|
||||||
| `SEARXNG_BASE` | `http://localhost:8888` | SearXNG |
|
| `SEARXNG_BASE` | `http://localhost:8888` | SearXNG |
|
||||||
| `QDRANT_URL` | `http://192.168.50.108:6333` | Qdrant on coordinator |
|
| `QDRANT_URL` | `http://localhost:6333` | Qdrant on the same node |
|
||||||
| `CAIC_AMQP_URL` | `amqp://caic:password@localhost:5672/caic` | RabbitMQ |
|
| `CAIC_AMQP_URL` | `amqp://caic:password@localhost:5672/caic` | RabbitMQ |
|
||||||
| `CAIC_COMFYUI_BASE` | `http://192.168.50.115:8188` | ComfyUI on worker |
|
| `CAIC_COMFYUI_BASE` | `http://localhost:8188` | ComfyUI (image gen) |
|
||||||
| `CAIC_COMFYUI_TIMEOUT` | `120` | ComfyUI generation timeout (seconds) |
|
| `CAIC_COMFYUI_TIMEOUT` | `120` | ComfyUI generation timeout (seconds) |
|
||||||
|
|
||||||
|
> **Current deployment (single-node):** all services run on jarvis (192.168.50.212). The cluster/AMQP/node-agent layer is dormant — it degrades gracefully and can be re-enabled for a multi-node cluster later.
|
||||||
|
|
||||||
## 2. Request/Response Architecture
|
## 2. Request/Response Architecture
|
||||||
|
|
||||||
### 2.1 Chat Pipeline (`/api/chat`)
|
### 2.1 Chat Pipeline (`/api/chat`)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# WireGuard Tunnel — Encrypted Node Transit
|
# WireGuard Tunnel — Encrypted Node Transit
|
||||||
|
|
||||||
|
> **Status: dormant (single-node deployment).** All cAIc services currently run on one node (jarvis, 192.168.50.212), so there is no inter-node traffic to encrypt. This document is kept as a reference for when a multi-node cluster is stood back up.
|
||||||
|
|
||||||
## Why
|
## Why
|
||||||
|
|
||||||
cAIc cluster traffic is plaintext today:
|
cAIc cluster traffic is plaintext today:
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ Scope: Active roadmap items and backlog.
|
|||||||
|
|
||||||
## In Progress
|
## In Progress
|
||||||
|
|
||||||
- **Image Generation Service** — Backend wired: cluster handlers, `POST /api/image/generate` proxy, node agent ComfyUI integration, hardware probe, 27 tests. ComfyUI install pending on corsair (RTX 5070 Ti).
|
- **Image Generation Service** — Backend wired: cluster handlers, `POST /api/image/generate` proxy, node agent ComfyUI integration, hardware probe, 27 tests. ComfyUI install pending on jarvis (single-node).
|
||||||
|
|
||||||
## Completed
|
## Completed
|
||||||
|
|
||||||
|
- **Single-node consolidation (2026-08-08)** — all cAIc services moved onto jarvis (192.168.50.212): llama-server, Qdrant, SearXNG, RabbitMQ, Ollama, ComfyUI. Config defaults (`COMFYUI_BASE`, AMQP URL, `NODE_NAME`) updated; cluster/AMQP layer left dormant (degrades gracefully). Project renamed `jarvisChat` → **cAIc**.
|
||||||
|
|
||||||
- **B8 (v0.19.3)** — Private Chat mode. Backend skip-DB/skip-RAG/skip-search flag, frontend PRIVATE badge, info popup.
|
- **B8 (v0.19.3)** — Private Chat mode. Backend skip-DB/skip-RAG/skip-search flag, frontend PRIVATE badge, info popup.
|
||||||
- **WireGuard TLS (v0.19.4)** — Self-signed WireGuard mesh encrypts all inter-node traffic (AMQP, inference, RPC). No code changes to cAIc. Documented in wiki/WireGuard-Setup.md + docker.md §5.4.
|
- **WireGuard TLS (v0.19.4)** — Self-signed WireGuard mesh encrypts all inter-node traffic (AMQP, inference, RPC). No code changes to cAIc. Documented in wiki/WireGuard-Setup.md + docker.md §5.4.
|
||||||
- **At-Rest Encryption (v0.20.0)** — AES-256-GCM encrypts all query-derived text at rest. crypto.py with auto-keygen, key stored as `heartbeat_interval_ms` in settings. All 12 storage paths wired (SQLite: messages, conversations, memories, upload_context; Qdrant: RAG chunks, ingest, upload). 200 tests pass.
|
- **At-Rest Encryption (v0.20.0)** — AES-256-GCM encrypts all query-derived text at rest. crypto.py with auto-keygen, key stored as `heartbeat_interval_ms` in settings. All 12 storage paths wired (SQLite: messages, conversations, memories, upload_context; Qdrant: RAG chunks, ingest, upload). 200 tests pass.
|
||||||
|
|||||||
+2
-2
@@ -11,13 +11,13 @@ responds to pings, and handles model swap commands.
|
|||||||
# hostname — defaults to socket.gethostname()
|
# hostname — defaults to socket.gethostname()
|
||||||
node_name = jarvis
|
node_name = jarvis
|
||||||
# LAN IP — defaults from socket
|
# LAN IP — defaults from socket
|
||||||
node_ip = 192.168.50.210
|
node_ip = 192.168.50.212
|
||||||
# "worker" (fixed)
|
# "worker" (fixed)
|
||||||
node_type = worker
|
node_type = worker
|
||||||
# comma-separated capability list
|
# comma-separated capability list
|
||||||
capabilities = llm
|
capabilities = llm
|
||||||
# RabbitMQ URL on coordinator
|
# RabbitMQ URL on coordinator
|
||||||
amqp_url = amqp://caic:password@192.168.50.108:5672/caic
|
amqp_url = amqp://caic:password@localhost:5672/caic
|
||||||
# port llama-server listens on
|
# port llama-server listens on
|
||||||
llama_port = 8081
|
llama_port = 8081
|
||||||
# path to GGUF model files
|
# path to GGUF model files
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ cAIc - RAG pipeline: Qdrant vector search + system prompt assembly.
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import uuid
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
@@ -45,7 +46,7 @@ async def _upsert_fact(fact: str, text: str, topic: str,
|
|||||||
if er.status_code != 200:
|
if er.status_code != 200:
|
||||||
continue
|
continue
|
||||||
vector = er.json()["embedding"]
|
vector = er.json()["embedding"]
|
||||||
pid = f"auto-{ts}-{i}"
|
pid = str(uuid.uuid5(uuid.NAMESPACE_DNS, f"auto-{ts}-{i}"))
|
||||||
payload = {
|
payload = {
|
||||||
"text": encrypt_text(chunk), "source": "auto_fact", "fact": fact,
|
"text": encrypt_text(chunk), "source": "auto_fact", "fact": fact,
|
||||||
"ingest_date": datetime.now(timezone.utc).isoformat(),
|
"ingest_date": datetime.now(timezone.utc).isoformat(),
|
||||||
@@ -124,7 +125,7 @@ async def confirm_fact_update(memory_id: int, old_fact: str, new_fact: str,
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def chunk_text(text: str, chunk_size: int = 512, overlap: int = 128) -> list:
|
def chunk_text(text: str, chunk_size: int = 200, overlap: int = 64) -> list:
|
||||||
words = text.split()
|
words = text.split()
|
||||||
target_words = int(chunk_size / 1.3)
|
target_words = int(chunk_size / 1.3)
|
||||||
overlap_words = int(overlap / 1.3)
|
overlap_words = int(overlap / 1.3)
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
"""JarvisChat routers - /api/chat streaming endpoint."""
|
"""cAIc routers - /api/chat streaming endpoint."""
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
"""JarvisChat routers - Cluster status API."""
|
"""cAIc routers - Cluster status API."""
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
import cluster
|
import cluster
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
JarvisChat - /v1/chat/completions router.
|
cAIc - /v1/chat/completions router.
|
||||||
OpenAI-compatible endpoint for IDE integration (Continue.dev, etc.).
|
OpenAI-compatible endpoint for IDE integration (Continue.dev, etc.).
|
||||||
Runs all requests through the full jC pipeline: profile + RAG + memory injection.
|
Runs all requests through the full jC pipeline: profile + RAG + memory injection.
|
||||||
FIM (fill-in-the-middle) requests are proxied directly — not persisted.
|
FIM (fill-in-the-middle) requests are proxied directly — not persisted.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""JarvisChat routers - Conversation CRUD."""
|
"""cAIc routers - Conversation CRUD."""
|
||||||
import logging
|
import logging
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
"""JarvisChat routers — Hardware self-assessment endpoint."""
|
"""cAIc routers — Hardware self-assessment endpoint."""
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
"""JarvisChat routers — Image generation proxy endpoint."""
|
"""cAIc routers — Image generation proxy endpoint."""
|
||||||
import base64
|
import base64
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -1,7 +1,8 @@
|
|||||||
"""JarvisChat routers - /api/ingest terminal command RAG hook."""
|
"""cAIc routers - /api/ingest terminal command RAG hook."""
|
||||||
import hashlib
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
import logging
|
import logging
|
||||||
|
import uuid
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
@@ -53,7 +54,7 @@ async def ingest_content(request: Request):
|
|||||||
continue
|
continue
|
||||||
vector = embed_resp.json()["embedding"]
|
vector = embed_resp.json()["embedding"]
|
||||||
chunk_hash = hashlib.md5(chunk.encode("utf-8")).hexdigest()[:12]
|
chunk_hash = hashlib.md5(chunk.encode("utf-8")).hexdigest()[:12]
|
||||||
point_id = f"ingest-{source}-{chunk_hash}-{i}"
|
point_id = str(uuid.uuid5(uuid.NAMESPACE_DNS, f"ingest-{source}-{chunk_hash}-{i}"))
|
||||||
payload = {"text": encrypt_text(chunk), "source": source, "ingest_date": datetime.now(timezone.utc).isoformat(), "type": "ingest"}
|
payload = {"text": encrypt_text(chunk), "source": source, "ingest_date": datetime.now(timezone.utc).isoformat(), "type": "ingest"}
|
||||||
payload.update(metadata)
|
payload.update(metadata)
|
||||||
upsert_resp = await client.put(
|
upsert_resp = await client.put(
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
"""JarvisChat routers - Memory CRUD API."""
|
"""cAIc routers - Memory CRUD API."""
|
||||||
from fastapi import APIRouter, HTTPException, Request
|
from fastapi import APIRouter, HTTPException, Request
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
JarvisChat routers - Model listing, system stats.
|
cAIc routers - Model listing, system stats.
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
"""JarvisChat routers - System prompt presets."""
|
"""cAIc routers - System prompt presets."""
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from fastapi import APIRouter, HTTPException, Request
|
from fastapi import APIRouter, HTTPException, Request
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
"""JarvisChat routers - Profile."""
|
"""cAIc routers - Profile."""
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from fastapi import APIRouter, HTTPException, Request
|
from fastapi import APIRouter, HTTPException, Request
|
||||||
from db import get_db
|
from db import get_db
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""JarvisChat routers — RAG corpus management admin endpoints."""
|
"""cAIc routers — RAG corpus management admin endpoints."""
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""JarvisChat routers - /api/search explicit search endpoint."""
|
"""cAIc routers - /api/search explicit search endpoint."""
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import uuid
|
import uuid
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
"""JarvisChat routers - Settings."""
|
"""cAIc routers - Settings."""
|
||||||
from fastapi import APIRouter, HTTPException, Request
|
from fastapi import APIRouter, HTTPException, Request
|
||||||
from db import get_db
|
from db import get_db
|
||||||
from security import read_json_body, BODY_LIMIT_DEFAULT_BYTES
|
from security import read_json_body, BODY_LIMIT_DEFAULT_BYTES
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
"""JarvisChat routers - Skills."""
|
"""cAIc routers - Skills."""
|
||||||
from fastapi import APIRouter, HTTPException, Request
|
from fastapi import APIRouter, HTTPException, Request
|
||||||
from db import get_db, get_setting, list_skills_with_state, set_skill_enabled
|
from db import get_db, get_setting, list_skills_with_state, set_skill_enabled
|
||||||
from security import read_json_body, BODY_LIMIT_DEFAULT_BYTES
|
from security import read_json_body, BODY_LIMIT_DEFAULT_BYTES
|
||||||
|
|||||||
+3
-2
@@ -1,7 +1,8 @@
|
|||||||
"""JarvisChat routers - /api/upload file/document attachment endpoint."""
|
"""cAIc routers - /api/upload file/document attachment endpoint."""
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import uuid
|
||||||
from datetime import datetime, timezone, timedelta
|
from datetime import datetime, timezone, timedelta
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
@@ -19,7 +20,7 @@ router = APIRouter()
|
|||||||
|
|
||||||
|
|
||||||
def _point_id(filename: str, chunk_idx: int) -> str:
|
def _point_id(filename: str, chunk_idx: int) -> str:
|
||||||
return f"upload-{filename}-{chunk_idx}"
|
return str(uuid.uuid5(uuid.NAMESPACE_DNS, f"upload-{filename}-{chunk_idx}"))
|
||||||
|
|
||||||
|
|
||||||
@router.post("/api/upload")
|
@router.post("/api/upload")
|
||||||
|
|||||||
Reference in New Issue
Block a user