The exam: eval/testset.jsonl holds 78 cases (A10 H28 L8 N5 P10 R10 T5 U2). workflow-map.html called it a 75-question exam in the two places it states the current total. Corrected. The two sentences describing how the exam "grew from 67 questions to 75" are left alone - that step is historically correct: 67 plus the eight live-model failures is 75, and the Phase 5 findings H26, H27 and H31 took it to 78 afterwards. The env files: .env.example said TWO 0600 files under ~/ai/ and listed pg-ai.env and api.env, but its own line 105 refers to langfuse.env, and README.md, scripts/deploy.sh and compose/langfuse-compose.yml all use three. The header was simply wrong; langfuse.env is now named in it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
165 lines
7.7 KiB
Text
165 lines
7.7 KiB
Text
# =============================================================================
|
|
# .env.example — every key, no values. Committed deliberately.
|
|
#
|
|
# On lin001 these live as THREE 0600 files under ~/ai/, never in Git:
|
|
# ~/ai/pg-ai.env the POSTGRES_* / AGENT_DB_* block
|
|
# ~/ai/langfuse.env the Langfuse SALT / NEXTAUTH_SECRET block (see below)
|
|
# ~/ai/api.env everything else
|
|
# Follow the ~/authelia/authelia.env precedent: chmod 0600, owned by azureuser.
|
|
# =============================================================================
|
|
|
|
# --- pg-ai (~/ai/pg-ai.env) --------------------------------------------------
|
|
POSTGRES_PASSWORD=
|
|
AGENT_DB_USER=agent_ro
|
|
AGENT_DB_PASSWORD=
|
|
|
|
# --- imh (PENDING — leave blank until Phase 4) -------------------------------
|
|
IMH_HOST=yau-sls-poc-imh
|
|
IMH_PORT=1433
|
|
IMH_DB=
|
|
IMH_USER=svc_agent_ro
|
|
IMH_PASSWORD=
|
|
USE_FIXTURES=true # flip to false when imh is live
|
|
|
|
# --- local Postgres ----------------------------------------------------------
|
|
PGHOST=pg-ai
|
|
PGPORT=5432
|
|
PGDATABASE=plant
|
|
PGUSER=agent_ro
|
|
PGPASSWORD=
|
|
|
|
# --- Azure OpenAI ------------------------------------------------------------
|
|
AZURE_OPENAI_ENDPOINT=
|
|
AZURE_OPENAI_API_KEY=
|
|
AZURE_OPENAI_API_VERSION=
|
|
CHAT_DEPLOYMENT= # flagship — final prose only
|
|
CHEAP_DEPLOYMENT= # nano/mini — classifier, entities, tool selection
|
|
EMBED_DEPLOYMENT= # text-embedding-3-small
|
|
|
|
# --- Documents / upload UI (Phase 9) -----------------------------------------
|
|
# Two roles, and the split IS the safety boundary. db/005 carries a trigger that
|
|
# stops uploads_rw setting superseded = FALSE, so the web path can make a
|
|
# document less visible and never more. ingest_rw is the only one that writes
|
|
# chunks or restores a document.
|
|
UPLOADS_DB_USER=uploads_rw
|
|
UPLOADS_DB_PASSWORD=
|
|
INGEST_DB_USER=ingest_rw
|
|
INGEST_DB_PASSWORD=
|
|
DOCS_INBOX=/inbox
|
|
MAX_UPLOAD_MB=25
|
|
|
|
# authelia | demo
|
|
# authelia the actor is Remote-User from the forward-auth headers. The design.
|
|
# demo the actor is TYPED ON THE FORM. Self-asserted and unverified -
|
|
# exactly what the design forbids. Rows are written as `demo:<name>`
|
|
# with actor_groups = 'DEMO-UNVERIFIED' so they can never be mistaken
|
|
# for authenticated ones, and every screen says so.
|
|
DOC_IDENTITY_MODE=authelia
|
|
# Who may approve, withdraw or restore. Comma-separated. EMPTY MEANS NOBODY and
|
|
# every mutating endpoint 403s - that is the intended failure direction. This
|
|
# stands in for the AD group AI_DocPublishers; swapping to the group later is a
|
|
# config change, not a code change.
|
|
DOC_PUBLISHERS=
|
|
|
|
# --- no-LLM stub mode --------------------------------------------------------
|
|
# OFF for anything real. With it on, no model is called: the class comes from
|
|
# the caller instead of the classifier and the prose is a fixed placeholder.
|
|
# Every answer carries stub_mode: true and a banner. See api/stub.py for what
|
|
# it proves and what it does not.
|
|
NO_LLM_STUB=false
|
|
|
|
# --- behaviour ---------------------------------------------------------------
|
|
CLASSIFIER_CONFIDENCE_THRESHOLD=0.7
|
|
# Where the CONTROLLED copy of a procedure actually lives - a site fact, the
|
|
# same for every document, so it is not in doc_chunks. Set this to the real
|
|
# DMS location. The default names who to ask, which is always true and never
|
|
# sends anybody to a place that does not exist.
|
|
CONTROLLED_COPY_LOCATION=
|
|
SITE_TIMEZONE=Australia/Sydney # storage UTC; convert once, in Cube
|
|
MAX_ROWS_RETURNED=5000
|
|
QUERY_TIMEOUT_SECONDS=30
|
|
MAX_OUTPUT_TOKENS=1200
|
|
|
|
# --- Cube --------------------------------------------------------------------
|
|
CUBEJS_API_SECRET=
|
|
CUBEJS_API_URL=http://cube:4000/cubejs-api/v1
|
|
|
|
# The upstream source Cube reads. ai-compose.yml says these come from this
|
|
# file, and this file did not list them - so the first person to deploy Cube
|
|
# had to work out from the compose comments and db/003_roles.sql what the
|
|
# service actually needed. While USE_FIXTURES=true the fixtures live in pg-ai,
|
|
# so this points at pg-ai with the cube_rw credentials from pg-ai.env.
|
|
# At Phase 4 the whole block becomes CUBEJS_DB_TYPE=mssql against imh.
|
|
CUBEJS_DB_TYPE=postgres
|
|
CUBEJS_DB_HOST=pg-ai
|
|
CUBEJS_DB_PORT=5432
|
|
CUBEJS_DB_NAME=plant
|
|
CUBEJS_DB_USER=cube_rw # CUBE_DB_USER in pg-ai.env
|
|
CUBEJS_DB_PASS= # CUBE_DB_PASSWORD in pg-ai.env
|
|
|
|
# NOT CUBEJS_EXT_DB_*. Cube v1 will not use Postgres as an external
|
|
# pre-aggregation store; cubestore does that job and needs no keys here.
|
|
# See the note above the cube service in compose/ai-compose.yml.
|
|
|
|
# --- Langfuse ----------------------------------------------------------------
|
|
# PROJECT keys, created in the Langfuse UI - not the server's own secrets
|
|
# (SALT, NEXTAUTH_SECRET), which live in langfuse.env and are a different
|
|
# thing. The two must be a MATCHED PAIR from the same key: a public key from
|
|
# one pair with a secret from another authenticates as neither.
|
|
#
|
|
# Langfuse shows the secret ONCE, at creation, and stores only a hash - the
|
|
# database keeps a masked form (sk-lf-...abcd) and nothing can recover it. If
|
|
# it is lost, generate a new pair; there is no way to read the old one back.
|
|
#
|
|
# Getting this wrong is silent in both directions. Keys absent -> _langfuse()
|
|
# returns None and every question is simply untraced. Keys present but wrong ->
|
|
# a client is built, Langfuse rejects it, and main.py swallows the exception on
|
|
# purpose, because observability must never break the answer path. Neither case
|
|
# logs anything. Confirm traces are ARRIVING; do not infer it from config.
|
|
LANGFUSE_HOST=http://langfuse:3000
|
|
LANGFUSE_PUBLIC_KEY=
|
|
LANGFUSE_SECRET_KEY=
|
|
LANGFUSE_SALT=
|
|
LANGFUSE_NEXTAUTH_SECRET=
|
|
LANGFUSE_DB_PASSWORD=
|
|
|
|
# --- ingest ------------------------------------------------------------------
|
|
AI_DOCS_ROOT=/datadisk/ai-docs
|
|
CHUNK_TOKEN_TARGET=800
|
|
|
|
# --- document upload (Phase 9) -----------------------------------------------
|
|
# Two more roles, because the component reachable from the internet must not be
|
|
# the component that can write doc_chunks. See db/004_doc_uploads.sql.
|
|
UPLOADS_DB_USER=uploads_rw # ai-api: the queue only, never doc_chunks
|
|
UPLOADS_DB_PASSWORD=
|
|
INGEST_DB_USER=ingest_rw # ai-docs-worker AND the ai-ingest CLI:
|
|
# doc_chunks + the queue. PGUSER is agent_ro
|
|
# and cannot INSERT - see BUILD-AI-CONTAINERS §16.1.
|
|
INGEST_DB_PASSWORD=
|
|
|
|
AI_DOCS_INBOX=/datadisk/ai-docs-inbox # writable staging; NOT the ingest root
|
|
AI_DOCS_WITHDRAWN=/datadisk/ai-docs-withdrawn # withdrawn files are moved, not deleted
|
|
MAX_UPLOAD_MB=50
|
|
UPLOAD_DISK_LIMIT_PCT=90 # refuse uploads above this on /datadisk
|
|
ALLOWED_UPLOAD_EXTENSIONS=.pdf,.docx,.md,.txt
|
|
|
|
# DIRECT membership only — Authelia does not resolve nested groups.
|
|
DOC_PUBLISHER_GROUP=AI_DocPublishers
|
|
# Who may curate the retrieval pool and run trimmed-pool demos. Defaults to the
|
|
# publisher group; point it at a narrower AD group if that should be separate.
|
|
DOC_ADMIN_GROUP=AI_DocPublishers
|
|
ALLOW_SELF_APPROVAL=false # uploader approving their own document
|
|
# Withdrawal (superseded = TRUE) is always available to the publisher group and
|
|
# is reversible. PURGE deletes chunks and is not. Leave it off unless there is a
|
|
# document that must not be in the database at all.
|
|
ALLOW_PURGE=false
|
|
|
|
# Retrieval pool. pool_enabled is orthogonal to superseded - see db/006_doc_pool.sql.
|
|
# Below this share of documents enabled, retrieval drops to an exact scan: the
|
|
# HNSW index is built over ALL embeddings and filters afterwards, so a heavily
|
|
# trimmed pool can return almost nothing. This bites in exactly the demo that
|
|
# trims the pool. Rehearse it.
|
|
POOL_EXACT_SCAN_BELOW_PCT=50
|
|
|
|
WORKER_POLL_SECONDS=10
|
|
WORKER_LEASE_MINUTES=30 # an `ingesting` row older than this is a dead worker
|