Commit Graph
45 Commits
Author SHA1 Message Date
haylan 71c9003bd8 Create dashscope-websearch-selfhost-options.md 2026-09-06 16:10:26 +02:00
haylanandClaude-Bot ed83fca05c feat(comfyui): add local image-gen service (#41)
Adds the comfyui service (yurisasc/comfyui-rocm7.1, gfx1201-tuned for the
R9700) on the ai-stack network, published on host port 8138 for a planned
external nginx route to comfy.home. Resolves PUID/PGID/VIDEO_GID/RENDER_GID
from the host in scripts/update.sh, same pattern as SEARXNG_LAN_IP.

OmniRoute provider registration (http://comfyui:8188) is still the same
manual dashboard/POST-/api/providers flow already used for llama-server —
not scripted, per docs/proxy-key-onboarding.md.

Part of wayfinder map #38.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015zCwaWJQuKgXDUfRPBqDS7
2026-09-05 22:40:07 +02:00
haylanandClaude-Bot 7d1ff2f54f docs(research): add image-gen backend survey and omniroute/qwen websearch notes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015zCwaWJQuKgXDUfRPBqDS7
2026-09-05 21:24:23 +02:00
haylanandClaude-Bot ac3f730f83 docs(research): recommend Qwen-Image FP8 for full-VRAM diffusion build
Closes issue #39 — with llama-server stopped and the full ~32GB R9700
available, Qwen-Image (Apache-2.0, 20B MMDiT) at FP8 precision (~25GB)
is the recommended upgrade from FLUX.1-schnell: it has the cleanest
license of the candidates and is the only one with a ComfyUI workflow
pre-validated specifically on this GPU architecture (gfx1201/R9700),
per kyuz0/amd-r9700-comfy. HunyuanImage-3.0 is ruled out (CUDA-only,
multi-GPU datacenter VRAM floor); Krea-2 flagged as promising but too
new for R9700-specific field evidence.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015zCwaWJQuKgXDUfRPBqDS7
2026-09-05 21:03:13 +02:00
haylanandClaude-Bot 451d5c7b28 docs(research): confirm lazytainer/omniroute idle-stop conflict (#40)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015zCwaWJQuKgXDUfRPBqDS7
2026-09-05 20:57:24 +02:00
haylanandClaude-Bot d8736b6dd7 fix(llama-server): quantize KV cache, restore full 262144 context
A real session hit 'request (66192 tokens) exceeds the available
context size (65536 tokens)' — --parallel 2 was splitting the
131072 total into 65536/slot, too small for actual usage.

Add --cache-type-k/v q8_0 (roughly halves KV memory) so the model's
true max context (262144, already the documented .env.example goal)
fits in the same ~25.6GB/6GB-headroom footprint the old 131072 fp16
setting used, instead of shrinking per-slot context to fit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-05 12:00:07 +02:00
haylanandClaude-Bot 5767f548c3 perf(llama-server): enable flash attention
Cuts prefill time with no accuracy cost, per markaicode.com's
llama.cpp timeout writeup — directly helps the prefill-vs-stream-idle
contention issue fixed in the prior two commits.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-05 11:32:17 +02:00
haylanandClaude-Bot 633292b291 fix(omniroute): raise stream-idle timeout to 180s
Contended prefill (see LLAMA_PARALLEL) can outrun the ~95s dashboard
value before first token, causing OmniRoute to cancel still-working
requests. Track it in git via STREAM_IDLE_TIMEOUT_MS instead of a
dashboard-only setting.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-05 11:29:12 +02:00
haylanandClaude-Bot 23e90fe8fb fix(llama-server): cap concurrent slots at 2 to curb prefill contention
Default --parallel of 4 let concurrent subagent requests split GPU
compute, pushing large-context prefill past OmniRoute's stream-idle
timeout and triggering cancel-on-both-sides.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-05 11:26:30 +02:00
haylan ae812cd9e0 feat(ctx): larger context size 2026-09-04 21:47:38 +02:00
haylan 9e9cac254b feat(stack): drop qdrant and embedding-server, use OmniRoute's built-in memory
OmniRoute's memory feature is self-contained: its bundled sqlite-vec
vector store plus a local ONNX embedding model (Transformers.js,
~400MB, fetched into the omniroute-data volume on first use) replace
the external qdrant + bge-small-en-v1.5 embedding-server pair, which
was never wired up in the dashboard. Two fewer containers, no
second GGUF download, no EMBEDDING_MODEL_FILE var. Memory stays
opt-in via the dashboard (Settings -> Memory, transformers source);
nothing here changes the gateway's static config.
2026-09-03 22:19:21 +02:00
haylanandClaude-Bot 9e1362c22c feat(omniroute): add dedicated embedding-server for memory feature
llama.cpp loads one model per process and the running Qwen3.8-27B chat
model isn't embedding-trained, so this is a second, CPU-only
llama-server instance (bge-small-en-v1.5, 384-dim) rather than adding
--embeddings to the chat one — see docs/research/litellm-knowledgebase.md
#3.

Downloader extended to fetch both GGUFs into the shared models volume.
No host port published — OmniRoute reaches it via the ai-stack network
DNS name (embedding-server:8081).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qx22CV9EUS3hGATucQav13
2026-09-03 21:43:20 +02:00
haylanandClaude-Bot 885de477ba feat(stack): bring back qdrant as OmniRoute's memory vector store
Bare service, no static config — wired up as a memory provider by
hand in the OmniRoute dashboard. Not published to the host; only
OmniRoute (same ai-stack network) talks to it. Also drops two stale
comments left over from the OMNIROUTE_PORT:4000 removal.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qx22CV9EUS3hGATucQav13
2026-09-03 21:19:06 +02:00
haylanandClaude-Bot c795993a64 fix(omniroute): publish API and dashboard ports directly, drop OMNIROUTE_PORT
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qx22CV9EUS3hGATucQav13
2026-09-03 20:49:25 +02:00
haylanandClaude-Bot c38375c0f4 fix(omniroute): add required WS bridge secret, memory ceiling, shutdown grace period
Cross-checked the deployment against OmniRoute's own docs
(docs/reference/ENVIRONMENT.md, docs/guides/DOCKER_GUIDE.md) and found
three gaps from the original migration:

- OMNIROUTE_WS_BRIDGE_SECRET was entirely missing - ENVIRONMENT.md marks
  it REQUIRED (production), for the internal Codex Responses WebSocket
  bridge. docker compose config validated fine without it (compose
  doesn't know omniroute's own required-var list), so this went
  unnoticed until checking the docs directly.
- No mem_limit/OMNIROUTE_MEMORY_MB - the Docker guide is explicit that
  the 1024MB default heap is dashboard-only sized; coding-agent workloads
  (every client this stack has) need OMNIROUTE_MEMORY_MB=8192 and a
  10+ GiB container ceiling. Set both.
- No stop_grace_period - the guide's --stop-timeout 40 equivalent, so
  SQLite WAL changes checkpoint back into the main DB file on shutdown
  instead of getting killed mid-write.

Redis checked and confirmed correctly absent - OmniRoute uses SQLite
only, no Redis anywhere in its docs.

Still open: whether API_PORT actually isolates /dashboard and /api/*
from the published port, or bridges everything through (see issue #31)
- OmniRoute's own ARCHITECTURE.md doesn't document split-port mode as a
real security boundary, and the live "[API Bridge] ... -> dashboard"
log line is ambiguous. Waiting on a live curl test against
proxy-ai.home before treating that as resolved.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VPZ6TogJiYxG8E4EQBB197
2026-09-03 20:37:49 +02:00
haylanandClaude-Bot 6132e6263e docs: fix gateway hostname to proxy-ai.home/proxy-ai.haylan.ch
Docs said proxy.ai.home (dot) throughout, but the actual NPM Proxy Host
is proxy-ai.home (hyphen) - confirmed with the user, who already has the
reverse proxy pointing :4000 at http://proxy-ai.home/.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VPZ6TogJiYxG8E4EQBB197
2026-09-03 20:28:21 +02:00
haylanandClaude-Bot 90ef1a1061 fix(omniroute): keep the gateway published on host port 4000
Not omniroute's own internal port (API_PORT stays at its default 20129,
unreconfigured) - just the Docker port mapping, so existing NPM/firewall
config pointed at :4000 keeps working without changes on that end. New
OMNIROUTE_PORT env var is the host side of "OMNIROUTE_PORT:API_PORT" in
docker-compose.yml's ports: entry.

Also corrected docs/proxy-key-onboarding.md's dashboard-access
instructions - DASHBOARD_PORT was never published to the host in the
first place, so "http://<host>:20128" was never actually reachable as
written; documented reaching it via the container's own bridge-network IP
or an SSH port-forward instead.

llama-server remains unexposed (no ports: entry, only expose:) -
unaffected by this change, confirming it stays that way.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VPZ6TogJiYxG8E4EQBB197
2026-09-03 20:17:08 +02:00
haylanandClaude-Bot 977e9d3dd7 fix(omniroute): healthcheck used python3, which the image doesn't have
Confirmed live on the R9700: omniroute starts up fine ("[API Bridge]
Listening on 0.0.0.0:20129") but docker reported it unhealthy forever -
the healthcheck's python3 -c "..." command can never run (which python3
wget curl node found only node in the image), so it failed every single
check regardless of actual app health.

Switched to a node-based TCP-connect check on the same port instead of an
HTTP GET against /healthz - OmniRoute's own Docker guide already treats a
bare TCP probe as an acceptable liveness check, and this sidesteps needing
to confirm /healthz's exact path/response shape on this image.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VPZ6TogJiYxG8E4EQBB197
2026-09-03 20:08:58 +02:00
haylanandClaude-Bot 3bbda098b3 feat(stack): remove Open WebUI and Qdrant
No longer needed - every client is a coding CLI behind the OmniRoute
gateway, not a chat UI. Drops the open-webui and qdrant services,
WEBUI_PORT/OPENWEBUI_OMNIROUTE_KEY env vars, and the openwebui-data/
qdrant-data volumes. Qdrant only ever served Open WebUI's own built-in
memory/RAG (unrelated to the gateway-level knowledgebase removed in
472e3a4), so it goes too rather than sit unused.

Docs updated: README, docs/network-access.md (ai.home/ai.haylan.ch
section was entirely about Open WebUI, rewritten around the gateway),
docs/proxy-key-onboarding.md, docs/proxy-request-priority.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VPZ6TogJiYxG8E4EQBB197
2026-09-03 19:55:31 +02:00
haylanandClaude-Bot 472e3a4738 feat(gateway): migrate LiteLLM to OmniRoute, drop the memory/knowledgebase feature
LiteLLM -> OmniRoute (issue #31, wayfinder map + research tickets #32-37):
replace the litellm/litellm-db services with omniroute, split-port mode
(API_PORT published/reverse-proxied, DASHBOARD_PORT never published -
tighter than litellm's old /ui NPM path-deny rule), 5 new secrets in place
of LITELLM_MASTER_KEY/LITELLM_SALT_KEY, llama-server/searxng registered as
omniroute providers post-boot (no static config.yaml equivalent). No
scripted per-workload key minting yet - omniroute's POST /api/keys needs a
dashboard session, not a static bearer key - so OPENWEBUI_OMNIROUTE_KEY is
a manual step for now (docs/proxy-key-onboarding.md).

Caveat carried into the map and README: OmniRoute's own docs
(docs/security/STEALTH_GUIDE.md, MITM-TPROXY-DECRYPT.md, PUBLIC_CREDS.md
on its release/v3.8.51 branch) describe shipped features for AI-provider
client-detection evasion, system-wide HTTPS interception via a locally
installed root CA, and hiding credentials from secret scanners. Proceeding
anyway was an explicit, informed user decision.

Also drops the gateway-level memory/knowledgebase feature entirely (user:
"I don't need it") - litellm-pgvector, pgvector-db, embedding-server,
scripts/ingest-memory.sh, vendor/litellm-pgvector/, docs/memory-
knowledgebase.md. Open WebUI's own qdrant-backed memory/RAG is unrelated
and untouched. litellm-config.yaml deleted (was kept as a rollback
reference, but there's no rollback path to a feature being deliberately
removed).

Not yet verified against real hardware - see issue #31's open tickets.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VPZ6TogJiYxG8E4EQBB197
2026-09-03 19:49:35 +02:00
haylanandClaude-Bot 4fe910a5f3 docs(agents): fix tea comment syntax, note map-edit race condition
tea comments create doesn't exist (add/a is the subcommand); a wayfinder
session hit this live resolving OmniRoute-migration tickets. Also note
that concurrent ticket resolutions racing to edit the same map issue
(a full-body replace, no append) can clobber each other's Decisions-so-far
lines -- observed the same session across 5 parallel research tickets.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VPZ6TogJiYxG8E4EQBB197
2026-09-03 19:29:10 +02:00
haylan 124053cf89 feat(scripts): auto-register memory-and-notes in litellm's DB for the Admin UI
The vector_store_registry block in litellm-config.yaml only seeds the
store into litellm's in-memory registry at boot — the Admin UI's Vector
Stores page (/ui/vector-stores) reads litellm's own DB
(LiteLLM_ManagedVectorStoresTable) instead, via /vector_store/list. A
config-only entry there gets silently deleted from memory the first time
anyone loads that page, since /vector_store/list treats the DB as the
source of truth and removes anything not also present there.

update.sh now registers it in the DB too, via POST /vector_store/new
(idempotent, same pattern as the existing virtual-key minting) — with the
literal resolved key, not the os.environ/... form used in
litellm-config.yaml, since the management API doesn't do config.yaml-style
substitution on request bodies.

Found in the process: /vector_store/update in this litellm version can't
touch litellm_params at all (VectorStoreUpdateRequest has no such field,
so PGVECTOR_API_KEY sent through it is silently dropped) — worth knowing
if this key ever needs rotating; documented in update.sh's comment.

Verified live: registered via the API, confirmed the row appears in
/vector_store/list (what the Admin UI page reads) with the real key, and
re-verified search still works end-to-end afterward.
2026-09-02 21:51:02 +00:00
haylan 47bdb22457 docs: record issue #24's smoke-test findings and local litellm-pgvector patches
memory-knowledgebase.md no longer says 'not yet verified' — it's been
smoke-tested end-to-end (direct search + the file_search tool on a chat
completion) and the bugs found are fixed in the preceding commits.
VENDORED.md documents the three local patches on top of the upstream
litellm-pgvector commit so a future re-vendor doesn't silently drop them.
2026-09-02 21:32:38 +00:00
haylan 7e8b5069d4 fix(scripts): update.sh never applied litellm-pgvector's db schema
litellm-pgvector's Dockerfile only runs 'prisma generate' (codegen) at
build time — nothing ever ran 'prisma db push' against pgvector-db, so the
vector_stores/embeddings tables plain didn't exist on a fresh deploy. Every
vector store call failed with 'relation "vector_stores" does not exist'.

update.sh now runs the push itself after bringing litellm-pgvector up.
2026-09-02 21:32:33 +00:00
haylan eaf11b6d4b fix(scripts): ingest-memory.sh never actually computed embeddings
Two bugs, either one fatal:
- litellm-pgvector's embeddings endpoints take a precomputed vector per
  chunk (they don't call the embedding model themselves) — the script
  posted {content, metadata} with no embedding field, guaranteed 422.
- The batch endpoint expects {"embeddings": [...]}; the script posted a
  bare JSON array as the body.

Now embeds each file's chunks via LiteLLM's /v1/embeddings first (using
LITELLM_PGVECTOR_EMBEDDING_KEY, already minted for exactly this) before
batch-inserting. Also made both source files optional — a missing file is
skipped, not a hard failure, since neither exists in this checkout yet.
2026-09-02 21:32:29 +00:00
haylan 213550e44b fix(litellm): prefix EMBEDDING__MODEL with openai/ for litellm-pgvector
litellm.aembedding can't infer a provider from a bare model name plus a
custom api_base — litellm-pgvector's embedding_service.py was hitting
'litellm.BadRequestError: LLM Provider NOT provided' on every query-time
embedding (i.e. every search). Same openai/ prefix already used for
qwen3.8-27b-local and local-embedding in litellm-config.yaml.
2026-09-02 21:32:23 +00:00
haylan 3eda4e3ec0 fix(litellm-pgvector): honor caller-supplied id on vector store create
POST /v1/vector_stores always minted a random UUID for the new store's id,
ignoring the request entirely. litellm-config.yaml's vector_store_registry
addresses this store by a fixed id (memory-and-notes), which could never
match a real row as a result — every search/write 404'd.

Added an optional id field to VectorStoreCreateRequest; create_vector_store
uses it when given, falls back to a random UUID otherwise (unchanged
behavior for callers that don't care).
2026-09-02 21:32:18 +00:00
haylan b627edb949 fix(litellm-pgvector): correct embedding vector dimension 1536 -> 768
schema.prisma hardcoded vector(1536), OpenAI ada-002's size. This stack's
actual embedding model is nomic-embed-text-v1.5, confirmed 768-dim live
against /v1/embeddings. Left as-is, the first insert after a schema push
would fail on a pgvector dimension mismatch.
2026-09-02 21:32:13 +00:00
haylan ec476c7950 fix(litellm): add missing api_key to vector_store_registry
Without it, litellm's pg_vector provider sent Authorization: Bearer None,
which round-tripped to the real api.openai.com and came back with
'Incorrect API key provided: None' — masking the actual problem and making
every vector store call fail. Points at litellm-pgvector's own
LITELLM_PGVECTOR_API_KEY (its SERVER_API_KEY), already present in .env.

Smoke-tested end-to-end against the live deploy for issue #24, alongside
the litellm-pgvector fixes in the following commits.
2026-09-02 21:32:08 +00:00
haylanandClaude-Bot e2dd106f74 feat(scripts): fold model downloads into update.sh, skip if already present
Today's embedding-server crash-loop (missing nomic-embed-text GGUF) was a
manual step nobody ran. update.sh now runs both downloader profiles
itself, every time, before bringing services up -- no separate command to
remember.

- docker-compose.yml: downloader/downloader-embedding commands gain a
  `test -f ... && skip || curl ...` guard, so re-running update.sh never
  re-downloads an existing model file.
- scripts/update.sh: runs both profiles after image pull/build, before
  service recreation.
- scripts/download-model.sh removed -- folded in, redundant standalone
  script.
- README.md / docs/memory-knowledgebase.md updated accordingly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018WHfjWrSEcGhCoeu6dQfDa
2026-09-02 23:07:53 +02:00
haylanandClaude-Bot fb7cfc9148 fix(litellm): raise qwen3.8-27b-local max_tokens floor 4096 -> 16384
Confirmed in llama-server logs: a real request hit exactly n_gen=4096
(the old floor) and returned no answer -- reasoning_content alone ate
the whole budget before any content was written, exactly the failure
mode this config's own comment predicted. 16384 is the user-chosen
middle ground between 8192 and 32768: ~10 min worst-case at ~26.7 t/s,
well under the 65536-token context window.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018WHfjWrSEcGhCoeu6dQfDa
2026-09-02 22:59:53 +02:00
haylanandClaude-Bot 30a8523433 fix(lazytainer): drop network_mode: host, join ai-stack (fixes self-ID panic)
lazytainer panics on every start with 'Could not determine container ID
of lazytainer': its self-detection (vmorganp/Lazytainer,
configureFromLabels()) matches os.Hostname() against the Docker
container-ID list, but network_mode: host makes the container inherit
the host machine's hostname instead of its own container ID, so the
match never succeeds. Upstream's own example compose file doesn't use
host networking (default bridge + published ports) — nothing about
lazytainer requires it.

It also couldn't have seen the traffic it's meant to watch: llama-server
has no published host port (issue #15) and only exists on the ai-stack
bridge network, which host networking has no visibility into. Joining
ai-stack instead fixes both problems at once.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018WHfjWrSEcGhCoeu6dQfDa
2026-09-02 22:55:38 +02:00
haylanandClaude-Bot c7848f356a chore(scripts): mark update.sh executable
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018WHfjWrSEcGhCoeu6dQfDa
2026-09-02 22:47:53 +02:00
haylanandClaude-Bot cb9b3a9045 fix(docs): update stale MEMORY_RETRIEVAL_EMBEDDING_KEY refs after litellm-pgvector revert
README.md and docs/proxy-key-onboarding.md were edited by later commits
(b996b1f, 24d749b) that the litellm-pgvector revert didn't touch, so they
still named the now-removed MEMORY_RETRIEVAL_EMBEDDING_KEY var. Left
docs/research/langchain-pgvector-vs-litellm-pgvector.md as-is — it's a
dated record of the decision being reversed, not live config.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018WHfjWrSEcGhCoeu6dQfDa
2026-09-02 22:46:10 +02:00
haylanandClaude-Bot e7983f0710 Revert "feat(knowledgebase): replace litellm-pgvector connector with memory-retrieval"
This reverts commit abeadc49c8.

Restores vendor/litellm-pgvector/ and the vector_store_registry wiring
(in-band file_search tool-call support) at the user's request, after
re-confirming against docs.litellm.ai/docs/completion/knowledgebase and
litellm-pgvector's own README that pg_vector is still not an in-process
vector_store_registry backend -- it requires this same standalone
connector service either way, so there is no simpler 'native' path that
was missed. Trading back in: 793 lines of vendored code, the untested
Prisma migration, and the git-context build risk noted in VENDORED.md
(all flagged as unverified against real hardware in issue #24), in
exchange for the file_search in-band tool call memory-retrieval did not
support.

Conflicts resolved on top of later commits (Redis, update.sh key-minting
fold-in):
- .env.example / docs/memory-knowledgebase.md: kept the auto-mint-via-
  update.sh language, renamed MEMORY_RETRIEVAL_* back to
  LITELLM_PGVECTOR_*.
- scripts/generate-secrets.sh: left deleted -- its job was folded into
  update.sh in 24d749b, unrelated to this revert.
- scripts/update.sh: renamed the MEMORY_RETRIEVAL_* secret/mint calls to
  LITELLM_PGVECTOR_* to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018WHfjWrSEcGhCoeu6dQfDa
2026-09-02 22:45:08 +02:00
haylanandClaude-Bot b4dc83949e feat(litellm): add Redis for router state/rate-limits/budgets/cache
New redis service (redis:7-alpine, password-protected, no persistence
volume — everything it holds is cache/coordination state). litellm gets
REDIS_HOST/REDIS_PORT/REDIS_PASSWORD, which is all LiteLLM needs to use it
for router state, rate limits/budgets, and cache invalidation — no
litellm-config.yaml block required (docs.litellm.ai/docs/proxy/caching).
REDIS_PASSWORD added to .env.example and update.sh's auto-generated
secrets.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 22:28:25 +02:00
haylanandClaude-Bot b996b1fe88 fix(scripts): update.sh now appends vars missing from .env, not just blank ones
set_if_blank/mint_key_if_blank used sed -i "s|^KEY=.*|...|", which only
replaces an existing KEY= line — a no-op if the line isn't there at all.
Any .env created before a var was added to .env.example (SEARXNG_LAN_IP,
PGVECTOR_DB_PASSWORD, MEMORY_RETRIEVAL_*, etc.) silently never got that var
filled in. Both helpers now check for "line missing" as a third case and
append it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 22:21:50 +02:00
haylanandClaude-Bot 24d749b2e0 feat(scripts): fold generate-secrets.sh into update.sh, auto-mint virtual keys
update.sh now creates .env from .env.example if missing, idempotently fills
in every random secret (same logic generate-secrets.sh had, now removed),
resolves SEARXNG_LAN_IP from search.home via the host's own DNS, and mints
OPENWEBUI_LITELLM_KEY / MEMORY_RETRIEVAL_EMBEDDING_KEY through LiteLLM's own
/key/generate API once litellm is up — no more manual Admin UI step for the
stack's own two workload keys. Docs updated to point at update.sh as the
one command; docs/proxy-key-onboarding.md keeps the manual/API steps as the
fallback and for onboarding other workloads.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 22:18:11 +02:00
haylanandClaude-Bot abeadc49c8 feat(knowledgebase): replace litellm-pgvector connector with memory-retrieval
Per docs/research/langchain-pgvector-vs-litellm-pgvector.md (issue #25):
the vendored litellm-pgvector connector (793 lines, Prisma migrations, a
fragile git-context build) is replaced by a ~90-line FastAPI service
(services/memory-retrieval/) wrapping langchain_postgres.PGVector directly
against pgvector-db. Same gateway boundary — it still calls litellm for
embeddings, nothing talks to Postgres or the model directly except this
service.

- New services/memory-retrieval/ (main.py, Dockerfile, requirements.txt):
  POST /ingest, POST /query, GET /health.
- docker-compose.yml: litellm-pgvector service replaced by memory-retrieval;
  pgvector-db and embedding-server untouched.
- litellm-config.yaml: vector_store_registry block removed (no
  langchain_postgres provider exists to register against; callers query
  memory-retrieval directly instead of an in-band file_search tool call —
  that mechanism was never confirmed working per issue #24 anyway).
- scripts/ingest-memory.sh rewritten for the new /ingest endpoint (same
  per-line chunking, no dedup).
- .env vars renamed: LITELLM_PGVECTOR_API_KEY/LITELLM_PGVECTOR_EMBEDDING_KEY
  -> MEMORY_RETRIEVAL_API_KEY/MEMORY_RETRIEVAL_EMBEDDING_KEY.
- vendor/litellm-pgvector/ removed entirely.
- docs/memory-knowledgebase.md updated for the new setup/query flow.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 22:09:25 +02:00
haylanandClaude-Bot e2a79eab4a docs(research): LangChain+pgvector-direct vs litellm-pgvector for issue #25
Verdict: switch. See docs/research/langchain-pgvector-vs-litellm-pgvector.md
for full reasoning, LOC comparison, and a concrete replacement service spec.
Research/doc only — no compose/config/vendor changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 22:02:58 +02:00
haylanandClaude-Bot 7247674a9f fix(litellm-pgvector): vendor the source instead of a remote git build context
The server's Docker/BuildKit couldn't do a git-context build of a public
github.com repo (fails with "could not read Username ... terminal prompts
disabled" — an auth-shaped error for what should be an anonymous clone).
Rather than debug that, vendor litellm-pgvector's small source tree
directly (vendor/litellm-pgvector/, see VENDORED.md for provenance/update
steps) and build from the local path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 21:50:45 +02:00
haylanandClaude-Bot b0e37b2f4c chore(scripts): add update.sh, hook it into agent/deploy workflow
One script to bring the running stack in sync after any change: git pull,
validate compose config, rebuild the litellm-pgvector local build, re-pull
images, recreate what changed. Documented in README's quickstart, and
CLAUDE.md now tells agents to run it after touching compose/config/scripts
rather than just describing a change as done.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 21:44:26 +02:00
haylanandClaude-Bot f508f5670a feat(litellm): wire SearXNG search, pgvector knowledgebase, and memory ingestion
- search_tools block in litellm-config.yaml (SearXNG as a first-class
  search_provider, standalone /v1/search endpoint, not a model tool) plus
  extra_hosts on the litellm service so it can resolve search.home.
- New embedding-server (nomic-embed-text-v1.5 on a second llama.cpp
  instance), pgvector-db, and litellm-pgvector services — LiteLLM's native
  knowledgebase feature has no Qdrant backend, so this is the only
  self-hosted path (docs/research/litellm-knowledgebase.md).
- vector_store_registry + local-embedding model entry in
  litellm-config.yaml, wiring it together.
- scripts/ingest-memory.sh to load data/memory.md and
  data/claude-legacy-memory.md into the knowledgebase.
- docs/memory-knowledgebase.md documenting the whole setup; data/
  gitignored (personal memory content, not meant to be committed).
- New .env vars (SEARXNG_LAN_IP, PGVECTOR_DB_PASSWORD,
  LITELLM_PGVECTOR_API_KEY, LITELLM_PGVECTOR_EMBEDDING_KEY,
  EMBEDDING_MODEL_FILE) and generate-secrets.sh support for the
  auto-generatable ones.

Resolves #22 and #23 (wayfinder map #21). Not yet verified on real
hardware — see #24.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 21:38:16 +02:00
haylanandClaude-Bot a3ecbc0e02 docs(research): investigate LiteLLM knowledgebase/vector_store feature for #23
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 21:26:39 +02:00
haylanandClaude-Bot 8c42f2518b research: LiteLLM web-search + SearXNG wiring (issue #22)
Answers whether SearXNG is natively supported by LiteLLM's /v1/search
feature, whether it's a model-tool or automatic retrieval, what
docker-compose.yml networking change is needed for the litellm container
to reach the LAN's search.home host, and how it interacts with this
project's known-flaky Qwen3.8-27B tool-calling.

Research only — litellm-config.yaml and docker-compose.yml are unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 21:25:30 +02:00