chore: jarvisChat → cAIc rename, single-node consolidation on jarvis, Qdrant UUID5 + chunk-size deploy fixes

This commit is contained in:
2026-08-08 09:56:39 -07:00
parent 44387919a8
commit e14ae2bd19
28 changed files with 72 additions and 48 deletions
+1 -1
View File
@@ -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
+5 -5
View File
@@ -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)
--- ---
+20 -3
View File
@@ -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
View File
@@ -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
+4 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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
+5 -3
View File
@@ -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`)
+2
View File
@@ -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:
+3 -1
View File
@@ -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
View File
@@ -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
+3 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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")