diff --git a/.env.example b/.env.example index 734feb8..32945dc 100644 --- a/.env.example +++ b/.env.example @@ -1,110 +1,833 @@ -# ----------------------------- -# Mega-project core / security -# ----------------------------- -NEUROFORGE_ADMIN_TOKEN=CHANGE_ME_ADMIN -NEUROFORGE_APP_API_KEY=CHANGE_ME_APP -NEUROFORGE_WORKER_TOKEN=CHANGE_ME_WORKER -NEUROFORGE_METRICS_TOKEN=CHANGE_ME_METRICS -KB_INTEGRATION_TOKEN=CHANGE_ME_KB_INTEGRATION -CONTROL_READ_TOKEN=CHANGE_ME_CONTROL_READ -NEUROFORGE_CLUSTER_TOKEN= -OPENAI_API_KEY= +############################################################################### +# GLPI NEUROFORGE MEGA v1.4.x - VOLLSTÄNDIGE .ENV.example +# +# Diese Datei ist die zentrale Konfiguration für docker compose. +# Sie enthält: +# - GLPI AI Agent (vollständige produktive Optionen) +# - NeuroForge / Vector Backend / Controlled Learning +# - Knowledge Editor +# - Control Center +# - optional SearXNG Research +# - optionale Codebase-Memory-UI +# +# SICHERER START: +# DRY_RUN=true +# AUTO_REPLY=false +# AUTO_PRIORITY=false +# AUTO_ESCALATION=false +# NEUROFORGE_RESEARCH_ENABLED=false +# NEUROFORGE_AUTONOMY_ENABLED=false +# +# WICHTIG: +# Interne Container-Adressen/Ports wie HTTP_ADDR, DATA_DIR, KNOWLEDGE_DIR, +# OLLAMA_URL, NEUROFORGE_URL und BRAIN_ACTIVITY_URL werden im Mega-Compose +# fest verdrahtet. Dadurch können alte Standalone-Werte die Container- +# Kommunikation nicht versehentlich beschädigen. +############################################################################### -# Staged vector migration: local | dual | neuroforge -KNOWLEDGE_VECTOR_BACKEND=dual -NEUROFORGE_NAMESPACE=glpi-agent -NEUROFORGE_SEARCH_K=128 -# true = keep processing with local/lexical fallback if NeuroForge is unavailable -# false = semantic backend failures are blocking -NEUROFORGE_FAIL_OPEN=true - -# ----------------------------- -# Shared local AI runtime -# ----------------------------- -OLLAMA_MODEL=gemma3 -OLLAMA_EMBEDDING_MODEL=embeddinggemma -OLLAMA_TIMEOUT=10m -OLLAMA_KEEP_ALIVE=10m -OLLAMA_NUM_PREDICT=768 -OLLAMA_JSON_RETRIES=1 - -# ----------------------------- -# GLPI Agent connection -# ----------------------------- -GLPI_URL=https://glpi.example.invalid -GLPI_API_VERSION=v2.3 -GLPI_CLIENT_ID= -GLPI_CLIENT_SECRET= -GLPI_USERNAME= -GLPI_PASSWORD= -GLPI_AGENT_USER_ID=0 -DRY_RUN=true -AUTO_CATEGORY=false -AUTO_REPLY=false -AUTO_PRIORITY=false -AUTO_ESCALATION=false -RAG_ENABLED=true -KNOWLEDGE_INDEX_MODE=incremental -KNOWLEDGE_MIN_SCORE=0.70 -KNOWLEDGE_ALLOWED_SOURCES=internal-kb - -# ----------------------------- -# Web access -# ----------------------------- -WEB_USERNAME=admin -WEB_PASSWORD=CHANGE_ME_AGENT_WEB -WEB_ALLOW_ANONYMOUS=false -BASIC_AUTH_USER=admin -BASIC_AUTH_PASSWORD=CHANGE_ME_KB_WEB - -# ----------------------------- -# Optional host ports -# ----------------------------- +############################################################################### +# 01. MEGA STACK - HOST PORTS / PFADE +############################################################################### CONTROL_HOST_PORT=8070 AGENT_HOST_PORT=8080 KNOWLEDGE_HOST_PORT=8081 NEUROFORGE_HOST_PORT=8090 OLLAMA_HOST_PORT=11434 +SEARXNG_HOST_PORT=8888 -# ----------------------------- -# Controlled learning / research -# ----------------------------- -# Enforces: no automatic learning from raw chat input or assistant output; -# explicit validated outcomes and research evidence keep distinct provenance. +# Gemeinsame produktive Knowledge-Quelle auf dem Docker-Host. +KB_DATA_PATH=./knowledge +KB_DATA_MOUNT_MODE=rw +KB_BACKUP_PATH=./backups +KB_STAGING_PATH=./staging + +############################################################################### +# 02. MEGA STACK - SECURITY / SERVICE TOKENS +############################################################################### +# Erzeugen z. B. mit: ./scripts/generate-secrets.sh +NEUROFORGE_ADMIN_TOKEN=CHANGE_ME_ADMIN_TOKEN +NEUROFORGE_APP_API_KEY=CHANGE_ME_APP_API_KEY +NEUROFORGE_WORKER_TOKEN=CHANGE_ME_WORKER_TOKEN +NEUROFORGE_METRICS_TOKEN=CHANGE_ME_METRICS_TOKEN +# Nur bei Clusterbetrieb erforderlich. +NEUROFORGE_CLUSTER_TOKEN= +KB_INTEGRATION_TOKEN=CHANGE_ME_KB_INTEGRATION_TOKEN +CONTROL_READ_TOKEN=CHANGE_ME_CONTROL_READ_TOKEN +# Optionaler externer OpenAI-Fallback. Leer = deaktiviert. +OPENAI_API_KEY= + +############################################################################### +# 03. SHARED OLLAMA RUNTIME +############################################################################### +# Dieses Modell wird von Agent, Knowledge und NeuroForge gemeinsam verwendet. +# Wenn du dein bisheriges Verhalten beibehalten willst, kannst du hier z. B. +# qwen3:8b statt gemma3 setzen. Das Modell muss vorher in Ollama vorhanden sein. +OLLAMA_MODEL=gemma3 +OLLAMA_EMBEDDING_MODEL=embeddinggemma +OLLAMA_TIMEOUT=10m +OLLAMA_MAX_CONCURRENT=1 +OLLAMA_NUM_PREDICT=768 +OLLAMA_JSON_RETRIES=1 +OLLAMA_KEEP_ALIVE=10m +OLLAMA_THINK=false + +############################################################################### +# 04. KNOWLEDGE EDITOR +############################################################################### +KB_APP_MODE=editor +APP_TITLE=Knowledge Base Editor +APP_SUBTITLE=GLPI NeuroForge Mega +AUTO_RELOAD_INTERVAL=60s + +# Für Produktion setzen. Leer würde die optionale Basic-Auth deaktivieren. +BASIC_AUTH_USER=admin +BASIC_AUTH_PASSWORD=CHANGE_ME_KB_WEB_PASSWORD_LONG + +AI_FALLBACK_ENABLED=true +# Wird im Mega-Compose intern auf http://ollama:11434 gesetzt. +OLLAMA_BASE_URL=http://ollama:11434 +OLLAMA_STAGING_AUTO_REPLY=false +OLLAMA_STAGING_MIN_SCORE=0.78 + +############################################################################### +# 05. NEUROFORGE VECTOR BACKEND / INTEGRATION +############################################################################### +# local | dual | neuroforge +KNOWLEDGE_VECTOR_BACKEND=dual +NEUROFORGE_NAMESPACE=glpi-agent +NEUROFORGE_TIMEOUT=15s +NEUROFORGE_SEARCH_K=128 +# true = bei NeuroForge-Ausfall lokale/lexikalische Evidenz weiterverwenden. +NEUROFORGE_FAIL_OPEN=true + +############################################################################### +# 06. CONTROLLED LEARNING / VALIDATED OUTCOMES +############################################################################### +# Verhindert automatisches Langzeitlernen aus rohem Chatinput/AI-Ausgaben. NEUROFORGE_CONTROLLED_LEARNING=true +# Separate gate for semantic goal-cycle memories. Required for manual/autonomous +# Goal cycles to learn while Controlled Learning remains enabled. +NEUROFORGE_GOAL_LEARNING_ENABLED=false -# Ticket -> AI proposal -> technician accept/correct -> NeuroForge learn. +# Ticket -> KI-Vorschlag -> Techniker bestätigt/korrigiert -> Trusted Outcome. OUTCOME_LEARNING_ENABLED=true -# false = technician sees an error when NeuroForge cannot persist the validated outcome. -# The local outcome audit is still retained with sync_status=failed. OUTCOME_LEARNING_FAIL_OPEN=false OUTCOME_LEARNING_MAX_OUTCOMES=2000 -# Active accepted/corrected outcomes are secondary reply evidence only. -# They never replace the approved-KB requirement for Auto-Reply. + +# Menschlich validierte Erfahrungen als sekundäre Evidenz abrufen. OUTCOME_RETRIEVAL_ENABLED=true OUTCOME_RETRIEVAL_SEARCH_K=6 OUTCOME_RETRIEVAL_MIN_SIMILARITY=0.58 -# true = continue with official KB/context if experience retrieval is unavailable. OUTCOME_RETRIEVAL_FAIL_OPEN=true -# Research is opt-in. Starting the SearXNG profile alone does not enable learning. +############################################################################### +# 07. OPTIONAL RESEARCH / SEARXNG / AUTONOMY +############################################################################### +# SearXNG-Container wird nur mit `docker compose --profile research ...` gestartet. +SEARXNG_IMAGE=docker.io/searxng/searxng:latest +SEARXNG_SECRET=CHANGE_ME_SEARXNG_LONG_RANDOM_SECRET + +# Research und Autonomy sind absichtlich getrennt. NEUROFORGE_RESEARCH_ENABLED=false NEUROFORGE_SEARXNG_ENABLED=false NEUROFORGE_SEARXNG_URL=http://searxng:8080 NEUROFORGE_RESEARCH_GOAL_ENABLED=true -# Separate switch for scheduled self-directed goal cycles. NEUROFORGE_AUTONOMY_ENABLED=false NEUROFORGE_AUTONOMY_INTERVAL_MINUTES=30 NEUROFORGE_RESEARCH_MAX_QUERIES=2 NEUROFORGE_RESEARCH_MAX_PAGES=4 -# Required only when the optional `research` compose profile is started. -# Pin this to a version/digest in production if reproducible images are required. -SEARXNG_IMAGE=docker.io/searxng/searxng:latest -SEARXNG_SECRET=CHANGE_ME_SEARXNG_LONG_RANDOM_SECRET -SEARXNG_HOST_PORT=8888 - -# Optional local developer-only Codebase Memory MCP/UI. It is not required by -# production services. For a host process reachable from Docker on Linux: +############################################################################### +# 08. OPTIONAL CODEBASE MEMORY MCP / ENGINEERING UI +############################################################################### +# Developer-only. Für den Produktivbetrieb nicht erforderlich. CODEBASE_MEMORY_URL= PUBLIC_CODEBASE_MEMORY_URL=http://localhost:9749 + +############################################################################### +# 09. AGENT - VOLLSTÄNDIGE KONFIGURATION +############################################################################### +# 09A. GLPI AI AGENT - ALLGEMEINER BETRIEB +############################################################################### +# true: +# Der Agent analysiert vollständig, schreibt aber keine Änderungen nach GLPI. +# +# false: +# Durch die Policy freigegebene Aktionen werden tatsächlich ausgeführt. +# +# Für Tests / Einführung: +# true +DRY_RUN=true +# Mögliche Werte: +# debug +# info +# warn +# error +LOG_LEVEL=info +# HTTP-Listener INNERHALB des Agent-Containers. +# Im Mega-Compose wird dieser Wert zusätzlich fest auf :8080 überschrieben. +# Der veröffentlichte Host-Port wird ausschließlich über AGENT_HOST_PORT gesteuert. +HTTP_ADDR=:8080 +# Persistentes Verzeichnis IM Container. +# +# Compose mountet: +# agent-data:/app/data +# +# Enthält unter anderem: +# - Knowledge-Index +# - Audit/Run-Daten +# - Category Learning +# - Managed Knowledge +# - GLPI-KB-Cache +DATA_DIR=/app/data +############################################################################### +# 06. AGENT WEBUI / API / DIAGNOSE +############################################################################### +# Benutzer für Agent-Dashboard, Knowledge-Verwaltung und Diagnose-Cockpit. +WEB_USERNAME=admin +WEB_PASSWORD=CHANGE_ME_AGENT_WEB_PASSWORD_LONG +# false: +# Anmeldung erforderlich. +# +# true: +# Weboberfläche ohne Authentifizierung erreichbar. +# +# In Produktion normalerweise false. +WEB_ALLOW_ANONYMOUS=false +# TrustedNet-Kennzeichnung vor automatisch ausgewählten Antworten. +# +# true: +# TrustedNet-KI-Badge wird vor Anrede und Antwort eingefügt. +# +# false: +# keine KI-Kennzeichnung. +AI_CONTENT_LABEL_ENABLED=true +############################################################################### +# 07. OPTIONALER GLPI-WEBHOOK +############################################################################### +# Optionales Shared Secret für eingehende GLPI-Webhooks. +# +# Der Absender muss dasselbe Secret z. B. über: +# X-Webhook-Secret +# übertragen. +# +# Leer lassen, falls kein Webhook verwendet wird. +WEBHOOK_SECRET= +############################################################################### +# 08. GLPI 11 / HIGH-LEVEL API / OAUTH2 +############################################################################### +GLPI_URL=https://glpi.example.invalid +# Verwendete GLPI High-Level API. +GLPI_API_VERSION=v2.3 +# OAuth2 Service Account. +GLPI_CLIENT_ID= +GLPI_CLIENT_SECRET= +GLPI_USERNAME= +GLPI_PASSWORD= +# Numerische GLPI-Benutzer-ID des Service-Accounts. +# +# Wird unter anderem benötigt, um Agent-Followups von menschlichen +# Followups unterscheiden zu können. +GLPI_AGENT_USER_ID=0 +# Nur für lokale Testsysteme ohne TLS. +# +# Produktion: +# false +GLPI_ALLOW_INSECURE_HTTP=false +############################################################################### +# 09. GLPI TICKET-POLLING +############################################################################### +# Fail-closed Whitelist erlaubter GLPI-Ticketstatus. +# +# Beispiel: +# 1 +# 1,2 +# +# Status 1 entspricht typischerweise "Neu". +GLPI_ALLOWED_STATUS_IDS=1 +# Polling-Intervall. +GLPI_POLL_INTERVAL=30s +# Maximale Anzahl Tickets pro Poll. +GLPI_POLL_LIMIT=50 +# Optionale serverseitige Vorfilterung. +# +# Die Agent-Policy prüft GLPI_ALLOWED_STATUS_IDS anschließend trotzdem selbst. +# +# Änderungen der Syntax immer gegen /api.php/doc der eigenen GLPI-Instanz +# prüfen. +GLPI_TICKET_FILTER=status.id==1 +# HTTP-Timeout für GLPI-Aufrufe. +GLPI_TIMEOUT=20s +############################################################################### +# 10. GLPI AI AGENT - OLLAMA-POOL +############################################################################### +# Einzelnode-Kompatibilität. Wird nur verwendet, wenn OLLAMA_URLS leer ist. +OLLAMA_URL=http://ollama:11434 + +# Mehrere Ollama-Instanzen, durch Komma getrennt. Alle Nodes sollten dieselbe +# Ollama-Version, dasselbe Chat-Modell und dasselbe Embedding-Modell besitzen. +# Beispiel für vorhandene Lenovo-Nodes: +# OLLAMA_URLS=http://10.20.30.21:11434,http://10.20.30.22:11434,http://10.20.30.23:11434 +OLLAMA_URLS= + +# Optionale lesbare Namen; Anzahl muss exakt zu OLLAMA_URLS passen. +# OLLAMA_NODE_NAMES=lenovo-01,lenovo-02,lenovo-03 +OLLAMA_NODE_NAMES= + +# Optionale Gewichte 1..100; nur für OLLAMA_ROUTING_MODE=weighted relevant. +# OLLAMA_NODE_WEIGHTS=1,1,1 +OLLAMA_NODE_WEIGHTS= + +# Routing-Modi: +# least_inflight = Node mit den wenigsten laufenden Requests (empfohlen) +# round_robin = zyklische Verteilung +# weighted = Verteilung anhand OLLAMA_NODE_WEIGHTS und Auslastung +# fastest_recent = bevorzugt die zuletzt schnellsten Nodes +OLLAMA_ROUTING_MODE=least_inflight + +# Maximale parallele Requests JE Node. Für integrierte GPUs/RAM-Sharing 1. +OLLAMA_NODE_MAX_INFLIGHT=1 + +# Regelmäßige Prüfung von /api/tags. +OLLAMA_NODE_HEALTH_INTERVAL=15s + +# Nach einem retryfähigen Netzwerk-/HTTP-Fehler wird der Node so lange nicht +# für neue Requests verwendet. +OLLAMA_NODE_FAILURE_COOLDOWN=30s + +# Maximalzeit für einen einzelnen Request an genau einen Node. Der übergeordnete +# Analyse-Timeout kann kürzer sein und hat dann Vorrang. +OLLAMA_NODE_REQUEST_TIMEOUT=10m + +# Bei Netzwerkfehlern, HTTP 408/429/5xx oder ungültigem Response-JSON auf einen +# anderen kompatiblen Node wechseln. +OLLAMA_FAILOVER_ENABLED=true + +# Maximale Anzahl verschiedener Nodes je logischem Request. 0 bedeutet: +# automatisch alle konfigurierten Nodes. Ein positiver Wert darf höchstens der +# Zahl der OLLAMA_URLS-Einträge entsprechen. +OLLAMA_FAILOVER_ATTEMPTS=0 + +# Bei abweichenden Chat-/Embedding-Modelldigests wird der Pool vollständig +# fail-closed. Für reproduzierbare Entscheidungen unbedingt true lassen. +OLLAMA_REQUIRE_SAME_MODEL_DIGEST=true + +# true: Jeder Node muss auch OLLAMA_EMBEDDING_MODEL installiert haben. +# Bei RAG empfohlen. false erlaubt Chat-only-Nodes; Embedding-Requests werden +# trotzdem nur an Nodes mit erkanntem Embedding-Modell gesendet. +OLLAMA_REQUIRE_EMBEDDING_MODEL=true + +# OLLAMA_MODEL ist bereits oben im gemeinsamen Compose-/Ollama-Bereich gesetzt: +# OLLAMA_MODEL=qwen3:8b +# Embedding-Modell für RAG. +# OLLAMA_EMBEDDING_MODEL=embeddinggemma # already configured in SHARED OLLAMA RUNTIME above + +# Modellspezifisches Retrieval-Prompting. +# auto = Modell automatisch erkennen; für embeddinggemma empfohlen. +# plain = keine modellspezifischen Retrieval-Prompts. +KNOWLEDGE_EMBEDDING_PROFILE=auto + +# Gesamtbudget für Ollama-Aufrufe und Fallback für Node-Request-Timeouts. +# OLLAMA_TIMEOUT ist bereits oben gesetzt. +# OLLAMA_MAX_CONCURRENT bleibt als Legacy-Alias für +# OLLAMA_NODE_MAX_INFLIGHT erhalten, falls der neue Wert nicht gesetzt ist. + +# Maximale Anzahl generierter Tokens für strukturierte Antworten. +# OLLAMA_NUM_PREDICT=768 # already configured in SHARED OLLAMA RUNTIME above +# Wiederholungen bei semantisch/strukturell fehlerhaftem Modell-JSON. +# Diese Wiederholungen sind von Netzwerk-Failover getrennt. +# OLLAMA_JSON_RETRIES=1 # already configured in SHARED OLLAMA RUNTIME above +# Ollama-Modell nach Benutzung im Speicher halten. +# OLLAMA_KEEP_ALIVE=10m # already configured in SHARED OLLAMA RUNTIME above +# Thinking bei unterstützten Modellen deaktivieren. +# OLLAMA_THINK=false # already configured in SHARED OLLAMA RUNTIME above +############################################################################### +# 11. KNOWLEDGE BASE / RAG - BASIS +############################################################################### +# Knowledge-Verzeichnis IM Agent-Container. +# +# Compose sollte hierhin KB_DATA_PATH mounten: +# ${KB_DATA_PATH:-./knowledge}:/app/knowledge:ro +KNOWLEDGE_DIR=/app/knowledge +# Gesamtes Retrieval-System aktivieren. +RAG_ENABLED=true +############################################################################### +# 12. EXTERNE KNOWLEDGE-KATEGORIEN +############################################################################### +# Verhalten bei String-/Fremdkategorien, z. B.: +# +# "AI-Staging" +# "Outlook" +# "E-Mail" +# "Signatur" +# +# Mögliche Werte: +# +# unscoped +# Artikel bleibt nutzbar. +# Fremdkategorien können als Retrieval-Metadaten dienen. +# +# skip +# Artikel mit unbekannten Kategorien überspringen. +# +# strict +# unbekannte Kategorie als Fehler behandeln. +# +# Für eine gemeinsam mit anderen Anwendungen verwendete KB: +# unscoped +KNOWLEDGE_CATEGORY_MODE=unscoped +# Optionales Mapping von Fremdkategorien auf GLPI-ITIL-Kategorie-IDs. +# +# Beispiel knowledge-category-map.json: +# +# { +# "Outlook": 12, +# "E-Mail": 12, +# "Active Directory": 2, +# "Security": [20,21] +# } +KNOWLEDGE_CATEGORY_MAP_FILE=/app/data/knowledge-category-map.json +# Optional bestimmte KB-Dateien ignorieren. +# +# Beispiele: +# KB-SEC-ATTCK-*.json +# legacy-*.json,external-only-*.json +# +# Leer: +# keine zusätzlichen Ignore-Regeln. +KNOWLEDGE_IGNORE_GLOBS= +############################################################################### +# 13. PERSISTENTER KNOWLEDGE-INDEX +############################################################################### +# Mögliche Werte: +# +# incremental +# Persistent gespeicherten Index sofort verwenden. +# Neue/geänderte Dateien anschließend inkrementell nachziehen. +# Für Produktion empfohlen. +# +# rebuild +# vollständigen Index neu erzeugen. +# +# readonly +# nur bestehenden Index verwenden, keine Änderungen übernehmen. +KNOWLEDGE_INDEX_MODE=incremental +# Anzahl Texte pro Embedding-Batch. +KNOWLEDGE_EMBED_BATCH_SIZE=64 +# Intervall für neue/geänderte/gelöschte Dateien. +# +# Beispiele: +# 30s +# 1m +# 5m +# +# 0: +# keinen automatischen Hintergrundscan durchführen. +KNOWLEDGE_INDEX_SCAN_INTERVAL=5m +############################################################################### +# 14. RETRIEVAL / DYNAMISCHE KANDIDATENAUSWAHL +############################################################################### +# Unterhalb dieses Retrieval-Scores wird eine KB nicht als geeigneter +# Kandidat betrachtet. +# +# Der Wert ist KEINE Wahrscheinlichkeit. +KNOWLEDGE_RETRIEVAL_FLOOR=0.30 +# Maximale Differenz zum besten Treffer. +# +# Beispiel: +# +# bester Treffer 0.82 +# MAX_GAP 0.20 +# dynamischer Cutoff 0.62 +# +# Ein Kandidat mit 0.55 würde dann nicht an die KI gesendet. +KNOWLEDGE_CANDIDATE_MAX_GAP=0.20 +# Maximale Anzahl Knowledge-Kandidaten, die tatsächlich an Ollama gehen. +KNOWLEDGE_TOP_K=6 +# Anzahl Kandidaten für Audit / Diagnose. +# +# Kann größer als KNOWLEDGE_TOP_K sein. +KNOWLEDGE_AUDIT_TOP_K=10 +############################################################################### +# 15. HYBRID-RETRIEVAL - RANKING-GEWICHTE +############################################################################### +# Die Werte beschreiben die Gewichtung beim KB-Ranking. +# +# Summe aktuell: +# 1.0 +# +# Fehlende Metadaten sollen nicht automatisch negativ bewertet werden. +# Embedding-/Chunk-Semantik. +KNOWLEDGE_WEIGHT_SEMANTIC=0.45 +# Ticket-Betreff gegenüber KB-Titel. +KNOWLEDGE_WEIGHT_TITLE=0.20 +# Lexikalische / sprachliche Übereinstimmung. +KNOWLEDGE_WEIGHT_LEXICAL=0.20 +# KB-Keywords. +KNOWLEDGE_WEIGHT_KEYWORDS=0.075 +# Kategorie-/Lernsignal. +KNOWLEDGE_WEIGHT_CATEGORY=0.075 +############################################################################### +# 16. FINALE EVIDENZ FÜR AUTO-REPLY +############################################################################### +# Mindestwert der FINALEN Evidenz. +# +# WICHTIG: +# Das ist nicht der reine Retrieval-Score. +# +# Die finale Evidenz kombiniert: +# - Retrieval +# - AI Confidence +# - Kategorieübereinstimmung +KNOWLEDGE_MIN_SCORE=0.70 +# Gewicht Retrieval. +KNOWLEDGE_EVIDENCE_WEIGHT_RETRIEVAL=0.45 +# Gewicht KI-Auswahl / KI-Confidence. +KNOWLEDGE_EVIDENCE_WEIGHT_AI=0.35 +# Gewicht Kategorieübereinstimmung. +KNOWLEDGE_EVIDENCE_WEIGHT_CATEGORY=0.20 +############################################################################### +# 17. KNOWLEDGE-CHUNKING +############################################################################### +# Ungefähre Anzahl Wörter pro Dokument-Chunk. +KNOWLEDGE_CHUNK_WORDS=160 +# Überlappung benachbarter Chunks. +KNOWLEDGE_CHUNK_OVERLAP_WORDS=30 +# Maximale Anzahl Chunks pro KB-Dokument. +KNOWLEDGE_MAX_CHUNKS_PER_DOC=24 +# Maximale Anzahl Query-Chunks bei sehr langen Tickets. +KNOWLEDGE_MAX_QUERY_CHUNKS=64 +# Maximale Anzahl Kategorien im Kategorie-Prompt. +CATEGORY_PROMPT_LIMIT=80 +############################################################################### +# 18. KNOWLEDGE-QUELLEN / TRUST POLICY +############################################################################### +# Quellen für normale Knowledge-Suche und mögliche Antwortkandidaten. +# Indexiert wird die Vereinigung mit KNOWLEDGE_CATEGORY_SOURCES. +# +# Beispiele: +# internal-kb +# glpi-kb +# runbook +# vendor-docs +KNOWLEDGE_ALLOWED_SOURCES=internal-kb,glpi-kb,vendor-docs,vendor-docs-ms,vendor-docs-linux,vendor-docs-sec +# Quellen, die ausschließlich die Kategorieentscheidung unterstützen. +# Ohne explizite Angabe wird aus Kompatibilitätsgründen KNOWLEDGE_ALLOWED_SOURCES verwendet. +# Mit "none" wird Knowledge-Einfluss auf die Kategorisierung deaktiviert. +KNOWLEDGE_CATEGORY_SOURCES=internal-category +# Nur diese Quellen dürfen grundsätzlich automatische Antworten liefern. +# +# Muss eine Teilmenge von KNOWLEDGE_ALLOWED_SOURCES sein. +# +# Beispiel zum kompletten Abschalten: +# KNOWLEDGE_AUTO_REPLY_SOURCES=none +KNOWLEDGE_AUTO_REPLY_SOURCES=internal-kb,glpi-kb,vendor-docs,vendor-docs-ms,vendor-docs-linux,vendor-docs-sec +# Webbasierte Bearbeitung von Agent-eigenen Knowledge-Artikeln. +# +# Diese werden unter: +# DATA_DIR/knowledge-managed +# gespeichert. +# +# Das statische KNOWLEDGE_DIR bleibt read-only. +KNOWLEDGE_WEB_EDIT_ENABLED=true +############################################################################### +# 19. GLPI KNOWLEDGE BASE CONNECTOR +############################################################################### +# GLPI-interne Knowledge Base synchronisieren. +GLPI_KB_ENABLED=true +# auto: +# Agent ermittelt die KnowbaseItem-Route aus /api.php/doc.json. +GLPI_KB_PATH=auto +# Optionaler serverseitiger GLPI-Filter. +# +# Leer: +# alle für den Service Account sichtbaren Artikel, begrenzt durch LIMIT. +GLPI_KB_FILTER= +# Maximale Anzahl GLPI-KB-Artikel. +GLPI_KB_LIMIT=500 +# Synchronisationsintervall. +GLPI_KB_SYNC_INTERVAL=10m +# source-Wert importierter GLPI-KB-Artikel. +GLPI_KB_SOURCE=glpi-kb +# true: +# GLPI-KB-Artikel können grundsätzlich Auto-Replies auslösen. +# +# Zusätzlich gelten weiterhin alle anderen Policy-Gates wie Retrieval, +# KI-Auswahl, Evidenz, Sprache, Stil und vorhandene Antworten. +GLPI_KB_AUTO_REPLY=false +# Whitelist der GLPI KNOWLEDGE-BASE-Kategorie-IDs. +# +# WICHTIG: +# Dies sind NICHT die ITIL-/Ticketkategorie-IDs. Ein kategorisierter Artikel +# ist genau dann grundsätzlich für Auto-Reply freigegeben, wenn mindestens +# eine seiner GLPI-KB-Kategorien hier enthalten ist. +# +# Mehrere Werte: +# 1,2,7 +GLPI_KB_AUTO_REPLY_CATEGORY_IDS=1 +# VERALTET / WIRD IGNORIERT: +# Ticket-/ITIL-Kategorien geben einen GLPI-Wissensartikel nicht mehr für +# Auto-Reply frei. Die Variable bleibt nur erhalten, damit alte .env-Dateien +# verständlich migriert werden können. Wert bitte leeren oder entfernen. +GLPI_KB_AUTO_REPLY_ITIL_CATEGORY_IDS= +# GLPI-KB-Artikel ohne Knowledge-Base-Kategorie bleiben standardmäßig gesperrt. +# +# true: +# Solche Artikel dürfen ausschließlich dann Auto-Reply verwenden, wenn ihre +# konkrete GLPI-KnowbaseItem-ID zusätzlich in +# GLPI_KB_AUTO_REPLY_UNCATEGORIZED_ARTICLE_IDS steht. +GLPI_KB_AUTO_REPLY_ALLOW_UNCATEGORIZED=false +# Explizite GLPI-KnowbaseItem-IDs für unkategorisierte Artikel. +# Beispiel: Das synchronisierte Dokument GLPI-KB-1 entspricht Artikel-ID 1. +# Diese Liste ist bei ALLOW_UNCATEGORIZED=true verpflichtend. +GLPI_KB_AUTO_REPLY_UNCATEGORIZED_ARTICLE_IDS= +############################################################################### +# 20. HUMAN-IN-THE-LOOP / KATEGORIE-LERNEN +############################################################################### +# Menschlich bestätigte/korrigierte Entscheidungen als Lernbeispiele verwenden. +# +# Der Agent lernt NICHT automatisch aus seinen eigenen unbestätigten +# Entscheidungen. +LEARNING_ENABLED=true +# Maximale Anzahl gespeicherter Beispiele. +LEARNING_MAX_EXAMPLES=500 +# Maximale Beispiele pro Kategorie im Prompt. +LEARNING_EXAMPLES_PER_CATEGORY=5 +############################################################################### +# 21. KOMMUNIKATIONSPOLICY +############################################################################### +# Erwartete Sprache von Auto-Reply-KBs. +COMMUNICATION_LANGUAGE=de-DE +# Erwarteter Kommunikationsstil. +COMMUNICATION_STYLE=formal +# Wird vor die Knowledge-Antwort gesetzt. +COMMUNICATION_SALUTATION=Guten Tag, +# Abschluss. +COMMUNICATION_CLOSING=Mit freundlichen Grüßen +COMMUNICATION_SIGNATURE=IT-Service +############################################################################### +# 22. OPERATIONAL CONTEXT - GLOBAL +############################################################################### +# Globaler Schalter für zusätzliche Betriebsinformationen: +# - Changes +# - Major Incidents +# - Requester-Geräte +# - Uptime Kuma +CONTEXT_ENABLED=true +# Timeout für Kontextabfragen. +CONTEXT_TIMEOUT=12s +# Mindestscore, ab dem Incident/Outage als für das Ticket relevant gilt. +CONTEXT_RELEVANCE_MIN_SCORE=0.20 +# true: +# Fehler einer aktivierten Kontextquelle blockieren Auto-Reply. +# +# Fail-closed und für Produktion empfohlen. +CONTEXT_BLOCK_AUTO_REPLY_ON_ERRORS=true +# true: +# relevante zentrale Störung blockiert individuelle Standardantwort. +CONTEXT_BLOCK_AUTO_REPLY_ON_INCIDENT=true +############################################################################### +# 23. GLPI CHANGE CALENDAR +############################################################################### +CHANGE_CALENDAR_ENABLED=true +# API-Route. +GLPI_CHANGE_PATH=/Assistance/Change +# Optionaler serverseitiger GLPI-Filter. +GLPI_CHANGE_FILTER= +# Maximale Anzahl geladener Changes. +GLPI_CHANGE_LIMIT=100 +# Betrachteter Zeitraum in der Vergangenheit. +CHANGE_LOOKBACK=72h +# Betrachteter Zeitraum in der Zukunft. +CHANGE_LOOKAHEAD=24h +############################################################################### +# 24. MAJOR INCIDENTS +############################################################################### +# Major Incidents über GLPI-Tickets ermitteln. +# +# Erst aktivieren, wenn GLPI_MAJOR_INCIDENT_FILTER getestet wurde. +MAJOR_INCIDENTS_ENABLED=false +# Expliziter Filter für Tickets, die als Major Incident gelten. +GLPI_MAJOR_INCIDENT_FILTER= +GLPI_MAJOR_INCIDENT_LIMIT=20 +############################################################################### +# 25. REQUESTER -> GERÄT / ASSET CONTEXT +############################################################################### +# Zusätzlich zu direkt verknüpften Ticket-Assets Geräte des Requesters suchen. +USER_DEVICE_CONTEXT_ENABLED=true +# Asset-Routen. +GLPI_USER_DEVICE_PATHS=/Assets/Computer +# {{user_id}} wird vom Agenten ersetzt. +GLPI_USER_DEVICE_FILTER_TEMPLATE=user.id=={{user_id}} +# Maximale Anzahl Geräte je Suche. +GLPI_USER_DEVICE_LIMIT=20 +############################################################################### +# 26. UPTIME KUMA +############################################################################### +# Globaler Schalter für Uptime-Kuma-Kontext. +UPTIME_KUMA_ENABLED=false +UPTIME_KUMA_URL=https://uptime.example.com +# Mögliche Werte: +# +# metrics +# authentifizierte Prometheus-Metrics. +# +# status_page +# öffentliche/publizierte Statusseiten. +UPTIME_KUMA_MODE=metrics +# Nur in metrics erforderlich. +UPTIME_KUMA_API_KEY= +# Nur in status_page erforderlich. +# +# Mehrere Slugs: +# it-services,network,applications +UPTIME_KUMA_STATUS_PAGES=it-services +UPTIME_KUMA_TIMEOUT=10s +# Maximale Anzahl gleichzeitig berücksichtigter Probleme. +UPTIME_KUMA_MAX_ISSUES=20 +# Maintenance ebenfalls als Kontext berücksichtigen. +UPTIME_KUMA_INCLUDE_MAINTENANCE=true + +# Optional: bei eindeutig passender Uptime-Kuma-Störung oder Wartung einen +# ausschließlich vom Betreiber vorgegebenen Text senden. Die KI erzeugt keinen +# Antworttext; sie wählt nur einen aktiven Kandidaten und liefert eine Confidence. +CONTEXT_STATUS_REPLY_ENABLED=false +CONTEXT_STATUS_REPLY_MIN_RELEVANCE=0.50 +CONTEXT_STATUS_REPLY_MIN_AI_CONFIDENCE=0.80 +# Finaler Score = Relevanz × KI-Confidence. +CONTEXT_STATUS_REPLY_MIN_FINAL_SCORE=0.45 +# Literal \n wird als Zeilenumbruch interpretiert. Verfügbare Platzhalter: +# {{service_name}}, {{status}}, {{status_page}}, {{message}}, +# {{incident_title}}, {{incident_content}}, {{last_heartbeat}} +CONTEXT_INCIDENT_REPLY_TEXT=Zu Ihrer Meldung liegt derzeit wahrscheinlich eine zentrale Störung bei {{service_name}} vor. Die Einschränkung kann damit zusammenhängen. Wir beobachten den Status. +CONTEXT_MAINTENANCE_REPLY_TEXT=Für {{service_name}} läuft derzeit eine Wartung. Die von Ihnen beschriebene Einschränkung kann damit zusammenhängen. Bitte testen Sie den Dienst nach Abschluss der Wartung erneut. +############################################################################### +# 27. POLICY-GATES +############################################################################### +# Automatische Kategorisierung zulassen. +AUTO_CATEGORY=true +# Automatische Antworten grundsätzlich zulassen. +# +# DRY_RUN=true verhindert trotzdem das tatsächliche Schreiben nach GLPI. +AUTO_REPLY=false +# Mindestconfidence der KI für Kategorieänderungen. +CATEGORY_CONFIDENCE=0.90 +# Mindestconfidence der KI für Antwortauswahl. +# +# Dies allein reicht NICHT für Auto-Reply. +# Zusätzlich gelten unter anderem: +# +# - Knowledge-Evidenz +# - Retrieval-Regeln +# - Source Policy +# - KB auto_reply +# - Kommunikationspolicy +# - Followup-Prüfung +# - Kontext-/Incident-Regeln +# - zweite Followup-Prüfung unmittelbar vor dem Schreiben +REPLY_CONFIDENCE=0.97 +############################################################################### +# 28. KI-PRIORISIERUNG +############################################################################### +# Separater KI-Lauf zur Empfehlung der GLPI-Priorität. Der Lauf wird im +# Diagnose-Cockpit unabhängig von Kategorie, Status und Antwort gespeichert. +PRIORITY_ENABLED=true +# Standardmäßig Shadow Mode: Empfehlung und Policy-Gates werden protokolliert, +# GLPI wird nicht verändert. Für Live-Schreibzugriffe zusätzlich DRY_RUN=false. +AUTO_PRIORITY=false +PRIORITY_CONFIDENCE=0.88 +# Eigener Fail-open-Timeout für diesen optionalen KI-Lauf. Kategorie und Antwort laufen danach weiter. +PRIORITY_ANALYSIS_TIMEOUT=45s +# Automatische Erhöhung je Ticketlauf; Herabstufungen sind grundsätzlich gesperrt. +PRIORITY_MAX_INCREASE=1 +# Nur kontrollierte, kommaseparierte Grundcodes dürfen eine Empfehlung tragen. +PRIORITY_ALLOWED_REASON_CODES=multiple_users_affected,site_affected,organization_affected,core_service_unavailable,security_incident_suspected,data_loss_possible,legal_or_regulatory_risk,business_deadline,no_workaround,safety_relevant,exam_or_event_critical +############################################################################### +# 29. ZEITGESTEUERTE KI-ESKALATION +############################################################################### +# Unabhängiger Scheduler. Er prüft offene Tickets auch ohne Änderung von date_mod. +ESCALATION_ENABLED=false +# Standardmäßig werden nur Diagnose-/Shadow-Läufe erzeugt. +# Live-Ausführung benötigt zusätzlich DRY_RUN=false und GLPI_AGENT_USER_ID. +AUTO_ESCALATION=false +ESCALATION_SCAN_INTERVAL=15m +# Mindestalter des Tickets seit date_creation, bevor es in den Eskalationsscan gelangt. +ESCALATION_MIN_AGE=4h +# Mindestdauer seit der letzten menschlichen Aktivität für den Grund +# no_human_response. SLA-, Security- und Major-Incident-Gründe können unabhängig +# davon greifen. Agent-Followups werden über GLPI_AGENT_USER_ID ausgenommen. +ESCALATION_MIN_INACTIVITY=2h +# Eigenes KI-Zeitbudget; blockiert die normalen Ticketläufe nicht unbegrenzt. +ESCALATION_ANALYSIS_TIMEOUT=45s +ESCALATION_CONFIDENCE=0.88 +ESCALATION_MAX_LEVEL=3 +# Zeitfenster vor time_to_resolve, in dem sla_at_risk deterministisch wahr wird. +ESCALATION_SLA_RISK_WINDOW=2h +# Aktionsspezifische Mindeststufen. +ESCALATION_SERVICE_OWNER_MIN_LEVEL=2 +ESCALATION_MANAGER_REVIEW_MIN_LEVEL=3 +# Mindest-Relevanz eines vom Kontextkollektor gelieferten Major Incidents. +ESCALATION_MAJOR_INCIDENT_MIN_RELEVANCE=0.50 +ESCALATION_ALLOWED_REASON_CODES=no_human_response,sla_at_risk,sla_breached,business_deadline,no_workaround,security_incident_suspected,unassigned,major_incident_candidate +# Jede Aktion muss einzeln freigegeben werden. Sichere Einführung: zunächst nur +# none,raise_priority; weitere Aktionen erst nach Konfiguration der Ziele aktivieren. +# Verfügbar: none,raise_priority,assign_second_level,assign_security_team, +# notify_service_owner,link_major_incident,request_manager_review +ESCALATION_ALLOWED_ACTIONS=none,raise_priority + +# Zielgruppen/-benutzer für Zuweisungs- und Benachrichtigungsaktionen. +# Es handelt sich um numerische GLPI-IDs. +ESCALATION_SECOND_LEVEL_GROUP_ID=0 +ESCALATION_SECURITY_GROUP_ID=0 +ESCALATION_SERVICE_OWNER_GROUP_ID=0 +ESCALATION_SERVICE_OWNER_USER_ID=0 +ESCALATION_MANAGER_REVIEW_GROUP_ID=0 +ESCALATION_MANAGER_REVIEW_USER_ID=0 + +# Zu jeder ausgeführten Aktion kann ein privater GLPI-Followup geschrieben werden. +ESCALATION_ADD_PRIVATE_FOLLOWUP=true +# Platzhalter: {{ticket_id}}, {{ticket_name}}, {{level}}, {{action}}, {{reason}}, +# {{reason_codes}}, {{major_incident_id}}, {{major_incident_name}}, +# {{major_incident_score}}. +# Literal \n wird in Template-Werten als Zeilenumbruch interpretiert. +ESCALATION_SECOND_LEVEL_NOTE=Automatische Eskalation Stufe {{level}}: Übergabe an den Second-Level-Support. Gründe: {{reason_codes}}. KI-Begründung: {{reason}} +ESCALATION_SECURITY_NOTE=Automatische Eskalation Stufe {{level}}: Übergabe an das Security-Team. Gründe: {{reason_codes}}. KI-Begründung: {{reason}} +ESCALATION_SERVICE_OWNER_NOTE=Automatische Eskalation Stufe {{level}}: Service Owner wurde zur Prüfung einbezogen. Gründe: {{reason_codes}}. KI-Begründung: {{reason}} +ESCALATION_MAJOR_INCIDENT_NOTE="Automatische Eskalation Stufe {{level}}: Verknüpfung mit Major Incident #{{major_incident_id}} ({{major_incident_name}}). Relevanz: {{major_incident_score}}. Gründe: {{reason_codes}}." +ESCALATION_MANAGER_REVIEW_NOTE=Automatische Eskalation Stufe {{level}}: Management-Review angefordert. Gründe: {{reason_codes}}. KI-Begründung: {{reason}} + +# Optionaler ausgehender Webhook für Service-Owner- und Management-Benachrichtigungen. +# Das Token wird nie über die Status-API ausgegeben. +ESCALATION_WEBHOOK_URL= +ESCALATION_WEBHOOK_BEARER_TOKEN= +ESCALATION_WEBHOOK_TIMEOUT=10s +# Nur für isolierte Testnetze; HTTPS ist der sichere Standard. +ESCALATION_WEBHOOK_ALLOW_INSECURE_HTTP=false + +# GLPI-Adapter für Zuweisungen. Die Feldnamen müssen zur OpenAPI-Beschreibung der +# konkreten GLPI-Installation passen. Unterstützte Payload-Formen: +# assigned_groups/assigned_users = Liste von {"id":...}; +# group/group_tech/user/user_tech = einzelnes {"id":...}. +GLPI_ESCALATION_GROUP_PATCH_FIELD=assigned_groups +GLPI_ESCALATION_USER_PATCH_FIELD=assigned_users + +# Installationsspezifischer Adapter für link_major_incident. Beide Werte sind +# erforderlich. Platzhalter im Pfad/JSON: {{ticket_id}}, {{source_ticket_id}}, +# {{major_incident_id}}, {{target_ticket_id}}. +GLPI_ESCALATION_ITIL_LINK_PATH= +GLPI_ESCALATION_ITIL_LINK_BODY= + +# Leer = GLPI_TICKET_FILTER verwenden. Für Produktion ausdrücklich auf offene, +# eskalierbare Status und die gewünschte Einheit beschränken. +GLPI_ESCALATION_FILTER= +GLPI_ESCALATION_LIMIT=100 +############################################################################### +# 30. WORKER / PRIORITÄTSQUEUE +############################################################################### +# Maximale Anzahl wartender Jobs. +QUEUE_SIZE=256 +# Parallele Ticket-Worker. Der Ollama-Pool kann nur so viele unabhängige +# Ticketpipelines gleichzeitig verteilen, wie Worker aktiv sind. Für drei +# gleichartige Nodes ist WORKERS=3 ein sinnvoller Lasttest; jeder Node bleibt +# zusätzlich durch OLLAMA_NODE_MAX_INFLIGHT begrenzt. +WORKERS=2 diff --git a/README.md b/README.md index cdfdbbe..d7c7452 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,8 @@ Standardmäßig bindet der Stack nur an `127.0.0.1`: Vor dem ersten produktiven Start bleiben in `.env.example` alle automatischen GLPI-Aktionen deaktiviert und `DRY_RUN=true`. +Die Repository-`.env.example` ist die **vollständige** Mega-Konfiguration und dokumentiert auch die weiterhin unterstützten Agent-Optionen aus älteren Installationen. Hinweise zur Migration und zu Compose-eigenen Containerwerten: [`docs/ENVIRONMENT.md`](docs/ENVIRONMENT.md) und [`docs/ENV-MIGRATION-FROM-LEGACY.md`](docs/ENV-MIGRATION-FROM-LEGACY.md). + ## Kontrollierter Vektor-Cutover `KNOWLEDGE_VECTOR_BACKEND` kennt drei Modi: @@ -170,3 +172,14 @@ python3 scripts/quality-replay.py docs/QUALITY-REPLAY-example.json --url http:// ## Bewusst begrenzte Autonomie Auch bei aktivierter Research-Autonomie veröffentlicht NeuroForge **nicht selbstständig** in die produktive Knowledgebase. Der technische Draft-Ingress ist vorhanden, aber der Übergang von einem konkreten Research-Run zu einem KB-Draft soll über einen expliziten Workflow/Job erfolgen. Das ist eine Governance-Entscheidung, kein fehlender Schreibweg. + +### Goal-Learning separat freigeben + +Controlled Learning deaktiviert Goal-Cycle-Lernen standardmäßig. Für bewusst freigegebene manuelle oder autonome Goal-Cycles: + +```env +NEUROFORGE_CONTROLLED_LEARNING=true +NEUROFORGE_GOAL_LEARNING_ENABLED=true +``` + +Damit bleibt rohes Chat-/Assistant-Lernen weiterhin deaktiviert. diff --git a/RELEASE-NOTES-v1.4.1.md b/RELEASE-NOTES-v1.4.1.md new file mode 100644 index 0000000..c1d3df4 --- /dev/null +++ b/RELEASE-NOTES-v1.4.1.md @@ -0,0 +1,9 @@ +# GLPI NeuroForge Mega v1.4.1 + +## Fix: Goal learning under Controlled Learning + +- Adds `NEUROFORGE_GOAL_LEARNING_ENABLED` as an explicit, independent gate. +- Keeps the safe default `false`. +- Allows goal-cycle learning while `NEUROFORGE_CONTROLLED_LEARNING=true` remains enabled. +- Does not re-enable raw chat input learning, assistant-response learning, or imports. +- Wires the flag through Docker Compose and exposes it read-only in Control Center config. diff --git a/docker-compose.yml b/docker-compose.yml index 0b10efd..18a3b91 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -48,6 +48,7 @@ services: NEUROFORGE_OLLAMA_CHAT_MODEL: ${OLLAMA_MODEL:-gemma3} NEUROFORGE_OLLAMA_EMBEDDING_MODEL: ${OLLAMA_EMBEDDING_MODEL:-embeddinggemma} NEUROFORGE_CONTROLLED_LEARNING: ${NEUROFORGE_CONTROLLED_LEARNING:-true} + NEUROFORGE_GOAL_LEARNING_ENABLED: ${NEUROFORGE_GOAL_LEARNING_ENABLED:-false} NEUROFORGE_RESEARCH_ENABLED: ${NEUROFORGE_RESEARCH_ENABLED:-false} NEUROFORGE_SEARXNG_ENABLED: ${NEUROFORGE_SEARXNG_ENABLED:-false} NEUROFORGE_SEARXNG_URL: ${NEUROFORGE_SEARXNG_URL:-http://searxng:8080} @@ -110,6 +111,10 @@ services: restart: unless-stopped env_file: .env environment: + # Internal container values are owned by Compose. This prevents legacy + # standalone .env values (for example HTTP_ADDR=:7080) from breaking + # service-to-service networking in the Mega stack. + HTTP_ADDR: :8080 DATA_DIR: /app/data KNOWLEDGE_DIR: /app/knowledge OLLAMA_URL: http://ollama:11434 @@ -133,7 +138,7 @@ services: - "127.0.0.1:${AGENT_HOST_PORT:-8080}:8080" volumes: - agent-data:/app/data - - ./knowledge:/app/knowledge:ro + - ${KB_DATA_PATH:-./knowledge}:/app/knowledge:ro depends_on: agent-data-init: condition: service_completed_successfully @@ -167,9 +172,9 @@ services: ports: - "127.0.0.1:${KNOWLEDGE_HOST_PORT:-8081}:8080" volumes: - - ./knowledge:/data/knowledge:rw - - ./staging:/data/staging:rw - - ./backups:/data/backups:rw + - ${KB_DATA_PATH:-./knowledge}:/data/knowledge:${KB_DATA_MOUNT_MODE:-rw} + - ${KB_STAGING_PATH:-./staging}:/data/staging:rw + - ${KB_BACKUP_PATH:-./backups}:/data/backups:rw depends_on: neuroforge: condition: service_healthy @@ -199,6 +204,7 @@ services: NEUROFORGE_SEARCH_K: ${NEUROFORGE_SEARCH_K:-128} NEUROFORGE_FAIL_OPEN: ${NEUROFORGE_FAIL_OPEN:-true} NEUROFORGE_CONTROLLED_LEARNING: ${NEUROFORGE_CONTROLLED_LEARNING:-true} + NEUROFORGE_GOAL_LEARNING_ENABLED: ${NEUROFORGE_GOAL_LEARNING_ENABLED:-false} OUTCOME_LEARNING_ENABLED: ${OUTCOME_LEARNING_ENABLED:-true} OUTCOME_RETRIEVAL_ENABLED: ${OUTCOME_RETRIEVAL_ENABLED:-true} OUTCOME_RETRIEVAL_SEARCH_K: ${OUTCOME_RETRIEVAL_SEARCH_K:-6} diff --git a/docs/CONTROLLED-AUTONOMY.md b/docs/CONTROLLED-AUTONOMY.md index f85c534..10f8184 100644 --- a/docs/CONTROLLED-AUTONOMY.md +++ b/docs/CONTROLLED-AUTONOMY.md @@ -151,6 +151,7 @@ Research darf außerdem nicht direkt produktive Knowledge-Artikel veröffentlich ```text NEUROFORGE_CONTROLLED_LEARNING=true +NEUROFORGE_GOAL_LEARNING_ENABLED=false OUTCOME_LEARNING_ENABLED=true OUTCOME_LEARNING_FAIL_OPEN=false NEUROFORGE_RESEARCH_ENABLED=false @@ -159,3 +160,18 @@ NEUROFORGE_AUTONOMY_ENABLED=false ``` Research anschließend gezielt aktivieren, beobachten und erst danach – falls gewünscht – Autonomy einschalten. + + +## Goal-Learning als separate Freigabe (v1.4.1) + +`NEUROFORGE_CONTROLLED_LEARNING=true` deaktiviert weiterhin rohes Chat-/Assistant-Lernen. +Goal-Cycles besitzen nun einen eigenen Schalter: + +```env +NEUROFORGE_CONTROLLED_LEARNING=true +NEUROFORGE_GOAL_LEARNING_ENABLED=true +``` + +Damit dürfen `RunGoalCycle` und autonome Goals semantische `goal-cycle`-Memories erzeugen, +ohne `LearnChatInputs`, `LearnChatResponses` oder `AllowImports` wieder zu aktivieren. +Für autonome Research-Goals sind zusätzlich die jeweiligen Research-/Autonomy-Schalter nötig. diff --git a/docs/ENV-MIGRATION-FROM-LEGACY.md b/docs/ENV-MIGRATION-FROM-LEGACY.md new file mode 100644 index 0000000..b3ca7ad --- /dev/null +++ b/docs/ENV-MIGRATION-FROM-LEGACY.md @@ -0,0 +1,80 @@ +# Migration einer bisherigen Agent-.env auf den Mega-Stack + +## Ergebnis der Prüfung + +Die 110 Variablennamen der bisherigen Agent-Konfiguration werden im aktuellen v1.4.x-Agenten +weiterhin verwendet. Das Problem lag nicht in entfernten Agent-Funktionen, sondern in der zu kurzen +Top-Level-`.env.example` des Mega-Projekts: 86 dieser 110 bisherigen Variablen waren dort nicht +explizit dokumentiert. + +Die Repository-`.env.example` ist deshalb jetzt die vollständige kanonische Vorlage. + +## Werte, die Compose intern besitzt + +Diese Werte sollten im Mega-Stack nicht zur Host-Konfiguration benutzt werden: + +| Variable | Mega-Containerwert | Externe Einstellung | +| --- | --- | --- | +| `HTTP_ADDR` | `:8080` | `AGENT_HOST_PORT` | +| `DATA_DIR` | `/app/data` | Docker Volume `agent-data` | +| `KNOWLEDGE_DIR` | `/app/knowledge` | `KB_DATA_PATH` | +| `OLLAMA_URL` | `http://ollama:11434` | Compose-Service `ollama` | +| `NEUROFORGE_URL` | `http://neuroforge:8080` | Compose-Service `neuroforge` | +| `NEUROFORGE_API_KEY` | aus `NEUROFORGE_APP_API_KEY` | `NEUROFORGE_APP_API_KEY` | +| `BRAIN_ACTIVITY_URL` | NeuroForge Event API | intern verdrahtet | + +Compose überschreibt `HTTP_ADDR` jetzt explizit. Dadurch kann eine alte Standalone-Konfiguration +mit `HTTP_ADDR=:7080` nicht mehr dazu führen, dass der Container auf einem anderen Port lauscht als +Compose weiterleitet. + +## Einstellungen mit relevantem Verhaltensunterschied + +Beim bloßen Wechsel von der alten `.env` auf die frühere kurze Mega-`.env.example` hätten sich unter +anderem diese Werte geändert: + +| Bereich | bisherige Konfiguration | Verhalten bei fehlender Variable / kurzer Mega-Vorlage | +| --- | --- | --- | +| GLPI KB Connector | aktiv | standardmäßig deaktiviert | +| GLPI-KB Auto-Reply | aktiv | standardmäßig deaktiviert | +| Knowledge Web Edit | aktiv | standardmäßig deaktiviert | +| Allowed Sources | mehrere interne/GLPI/Vendor-Quellen | nur `internal-kb` | +| Auto-Reply Sources | mehrere Quellen | nur `internal-kb` | +| Category Confidence | `0.70` | Code-Default `0.90` | +| Reply Confidence | `0.70` | Code-Default `0.97` | +| Change Lookback | `72h` | Code-Default `48h` | +| Chat-Modell | bisher z. B. `qwen3:8b` | Mega-Vorlage `gemma3` | + +Diese Unterschiede sind nicht automatisch falsch, müssen aber bewusst entschieden werden. + +## Neue Mega-Einstellungen + +Neu gegenüber der bisherigen Agent-Only-Konfiguration sind insbesondere: + +- NeuroForge Admin/App/Worker/Metrics Tokens +- `KNOWLEDGE_VECTOR_BACKEND=local|dual|neuroforge` +- NeuroForge Namespace/Search/Failure Policy +- Controlled Learning +- Human-validated Outcome Learning +- Outcome Retrieval +- Research/SearXNG +- getrennte Autonomy-Aktivierung +- Knowledge Integration Token +- scoped `CONTROL_READ_TOKEN` +- Control Center / NeuroForge / Knowledge Host Ports +- optionale Codebase-Memory-UI + +## Empfohlene Migration + +1. Neue `.env` aus der vollständigen `.env.example` erzeugen. +2. Neue Service-Tokens mit `./scripts/generate-secrets.sh` erzeugen. +3. GLPI-Zugangsdaten neu eintragen. +4. Gewünschte alte Retrieval-/Context-/Communication-Werte bewusst übertragen. +5. Zunächst `DRY_RUN=true` und alle automatischen Schreibaktionen deaktiviert lassen. +6. GLPI KB Sync, Knowledge Retrieval, Outcome Retrieval und NeuroForge im `dual`-Modus prüfen. +7. Erst danach einzelne Schreibfunktionen kontrolliert aktivieren. + +## Credential-Hygiene + +Zugangsdaten, die in Chat, Tickets, CI-Logs oder Screenshots veröffentlicht wurden, gelten nicht mehr +als geheim und sollten vor Produktionsbetrieb rotiert werden. Das betrifft insbesondere GLPI +Client-Secrets/Passwörter, Web-Passwörter und Webhook-Secrets. diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md new file mode 100644 index 0000000..82bf767 --- /dev/null +++ b/docs/ENVIRONMENT.md @@ -0,0 +1,65 @@ +# Environment configuration (v1.4.x) + +The repository-level `.env.example` is the canonical configuration template for the Mega stack. +It intentionally includes the complete GLPI Agent configuration plus NeuroForge, controlled-learning, +Knowledge Editor, Control Center and optional Research/SearXNG settings. + +## Important migration rule + +Do not copy the old standalone agent `.env` unchanged into the Mega stack without reviewing it. +The old variables are still supported, but container-internal values are now owned by Compose: + +- `HTTP_ADDR=:8080` +- `DATA_DIR=/app/data` +- `KNOWLEDGE_DIR=/app/knowledge` +- `OLLAMA_URL=http://ollama:11434` +- `NEUROFORGE_URL=http://neuroforge:8080` +- `NEUROFORGE_API_KEY` is derived from `NEUROFORGE_APP_API_KEY` +- Brain-activity endpoints are wired internally by Compose + +The host-facing ports are configured separately with `AGENT_HOST_PORT`, `KNOWLEDGE_HOST_PORT`, +`CONTROL_HOST_PORT`, `NEUROFORGE_HOST_PORT`, `OLLAMA_HOST_PORT` and `SEARXNG_HOST_PORT`. + +## First setup + +```sh +cp .env.example .env +./scripts/generate-secrets.sh +``` + +Copy the generated values into `.env`, then configure the required GLPI credentials: + +- `GLPI_URL` +- `GLPI_CLIENT_ID` +- `GLPI_CLIENT_SECRET` +- `GLPI_USERNAME` +- `GLPI_PASSWORD` +- `GLPI_AGENT_USER_ID` before enabling Auto Reply / escalation writes + +Keep `DRY_RUN=true`, `AUTO_REPLY=false`, `AUTO_PRIORITY=false` and `AUTO_ESCALATION=false` +for the first integration tests. + +## Legacy behavior that is no longer represented by defaults + +A migration from an older agent `.env` can materially change behavior if only the short Mega template +is used. In particular review: + +- `GLPI_KB_ENABLED` +- `GLPI_KB_AUTO_REPLY` +- `GLPI_KB_AUTO_REPLY_CATEGORY_IDS` +- `KNOWLEDGE_ALLOWED_SOURCES` +- `KNOWLEDGE_AUTO_REPLY_SOURCES` +- `KNOWLEDGE_WEB_EDIT_ENABLED` +- `CATEGORY_CONFIDENCE` +- `REPLY_CONFIDENCE` +- Context / Change / Uptime Kuma options +- Priority and escalation policy +- Communication policy + +The canonical `.env.example` now contains these settings explicitly. + +## Secrets + +Never commit `.env`. The tracked file must remain `.env.example` only. +If credentials were pasted into issue trackers, chats, CI logs, shell history or screenshots, +rotate them before production use. diff --git a/go.work b/go.work index b83d247..917ca19 100644 --- a/go.work +++ b/go.work @@ -1,4 +1,4 @@ -go 1.26 +go 1.23 use ( ./platform/neuroforge diff --git a/patches/v1.4.0-envfix-to-v1.4.1.diff b/patches/v1.4.0-envfix-to-v1.4.1.diff new file mode 100644 index 0000000..d6a7551 --- /dev/null +++ b/patches/v1.4.0-envfix-to-v1.4.1.diff @@ -0,0 +1,145 @@ +diff -ruN '--exclude=patches' /mnt/data/_inspect140/glpi-neuroforge-mega-v1.4.0-gitea-envfix/.env.example /mnt/data/glpi-neuroforge-mega-v1.4.1-gitea/.env.example +--- /mnt/data/_inspect140/glpi-neuroforge-mega-v1.4.0-gitea-envfix/.env.example 2026-08-26 18:29:23.000000000 +0000 ++++ /mnt/data/glpi-neuroforge-mega-v1.4.1-gitea/.env.example 2026-08-26 19:16:45.040061919 +0000 +@@ -105,6 +105,9 @@ + ############################################################################### + # Verhindert automatisches Langzeitlernen aus rohem Chatinput/AI-Ausgaben. + NEUROFORGE_CONTROLLED_LEARNING=true ++# Separate gate for semantic goal-cycle memories. Required for manual/autonomous ++# Goal cycles to learn while Controlled Learning remains enabled. ++NEUROFORGE_GOAL_LEARNING_ENABLED=false + + # Ticket -> KI-Vorschlag -> Techniker bestätigt/korrigiert -> Trusted Outcome. + OUTCOME_LEARNING_ENABLED=true +diff -ruN '--exclude=patches' /mnt/data/_inspect140/glpi-neuroforge-mega-v1.4.0-gitea-envfix/README.md /mnt/data/glpi-neuroforge-mega-v1.4.1-gitea/README.md +--- /mnt/data/_inspect140/glpi-neuroforge-mega-v1.4.0-gitea-envfix/README.md 2026-08-26 18:30:20.000000000 +0000 ++++ /mnt/data/glpi-neuroforge-mega-v1.4.1-gitea/README.md 2026-08-26 19:16:45.040936022 +0000 +@@ -172,3 +172,14 @@ + ## Bewusst begrenzte Autonomie + + Auch bei aktivierter Research-Autonomie veröffentlicht NeuroForge **nicht selbstständig** in die produktive Knowledgebase. Der technische Draft-Ingress ist vorhanden, aber der Übergang von einem konkreten Research-Run zu einem KB-Draft soll über einen expliziten Workflow/Job erfolgen. Das ist eine Governance-Entscheidung, kein fehlender Schreibweg. ++ ++### Goal-Learning separat freigeben ++ ++Controlled Learning deaktiviert Goal-Cycle-Lernen standardmäßig. Für bewusst freigegebene manuelle oder autonome Goal-Cycles: ++ ++```env ++NEUROFORGE_CONTROLLED_LEARNING=true ++NEUROFORGE_GOAL_LEARNING_ENABLED=true ++``` ++ ++Damit bleibt rohes Chat-/Assistant-Lernen weiterhin deaktiviert. +diff -ruN '--exclude=patches' /mnt/data/_inspect140/glpi-neuroforge-mega-v1.4.0-gitea-envfix/RELEASE-NOTES-v1.4.1.md /mnt/data/glpi-neuroforge-mega-v1.4.1-gitea/RELEASE-NOTES-v1.4.1.md +--- /mnt/data/_inspect140/glpi-neuroforge-mega-v1.4.0-gitea-envfix/RELEASE-NOTES-v1.4.1.md 1970-01-01 00:00:00.000000000 +0000 ++++ /mnt/data/glpi-neuroforge-mega-v1.4.1-gitea/RELEASE-NOTES-v1.4.1.md 2026-08-26 19:16:45.041115446 +0000 +@@ -0,0 +1,9 @@ ++# GLPI NeuroForge Mega v1.4.1 ++ ++## Fix: Goal learning under Controlled Learning ++ ++- Adds `NEUROFORGE_GOAL_LEARNING_ENABLED` as an explicit, independent gate. ++- Keeps the safe default `false`. ++- Allows goal-cycle learning while `NEUROFORGE_CONTROLLED_LEARNING=true` remains enabled. ++- Does not re-enable raw chat input learning, assistant-response learning, or imports. ++- Wires the flag through Docker Compose and exposes it read-only in Control Center config. +diff -ruN '--exclude=patches' /mnt/data/_inspect140/glpi-neuroforge-mega-v1.4.0-gitea-envfix/docker-compose.yml /mnt/data/glpi-neuroforge-mega-v1.4.1-gitea/docker-compose.yml +--- /mnt/data/_inspect140/glpi-neuroforge-mega-v1.4.0-gitea-envfix/docker-compose.yml 2026-08-26 18:27:35.000000000 +0000 ++++ /mnt/data/glpi-neuroforge-mega-v1.4.1-gitea/docker-compose.yml 2026-08-26 19:16:45.040327469 +0000 +@@ -48,6 +48,7 @@ + NEUROFORGE_OLLAMA_CHAT_MODEL: ${OLLAMA_MODEL:-gemma3} + NEUROFORGE_OLLAMA_EMBEDDING_MODEL: ${OLLAMA_EMBEDDING_MODEL:-embeddinggemma} + NEUROFORGE_CONTROLLED_LEARNING: ${NEUROFORGE_CONTROLLED_LEARNING:-true} ++ NEUROFORGE_GOAL_LEARNING_ENABLED: ${NEUROFORGE_GOAL_LEARNING_ENABLED:-false} + NEUROFORGE_RESEARCH_ENABLED: ${NEUROFORGE_RESEARCH_ENABLED:-false} + NEUROFORGE_SEARXNG_ENABLED: ${NEUROFORGE_SEARXNG_ENABLED:-false} + NEUROFORGE_SEARXNG_URL: ${NEUROFORGE_SEARXNG_URL:-http://searxng:8080} +@@ -203,6 +204,7 @@ + NEUROFORGE_SEARCH_K: ${NEUROFORGE_SEARCH_K:-128} + NEUROFORGE_FAIL_OPEN: ${NEUROFORGE_FAIL_OPEN:-true} + NEUROFORGE_CONTROLLED_LEARNING: ${NEUROFORGE_CONTROLLED_LEARNING:-true} ++ NEUROFORGE_GOAL_LEARNING_ENABLED: ${NEUROFORGE_GOAL_LEARNING_ENABLED:-false} + OUTCOME_LEARNING_ENABLED: ${OUTCOME_LEARNING_ENABLED:-true} + OUTCOME_RETRIEVAL_ENABLED: ${OUTCOME_RETRIEVAL_ENABLED:-true} + OUTCOME_RETRIEVAL_SEARCH_K: ${OUTCOME_RETRIEVAL_SEARCH_K:-6} +diff -ruN '--exclude=patches' /mnt/data/_inspect140/glpi-neuroforge-mega-v1.4.0-gitea-envfix/docs/CONTROLLED-AUTONOMY.md /mnt/data/glpi-neuroforge-mega-v1.4.1-gitea/docs/CONTROLLED-AUTONOMY.md +--- /mnt/data/_inspect140/glpi-neuroforge-mega-v1.4.0-gitea-envfix/docs/CONTROLLED-AUTONOMY.md 2026-08-26 04:47:34.000000000 +0000 ++++ /mnt/data/glpi-neuroforge-mega-v1.4.1-gitea/docs/CONTROLLED-AUTONOMY.md 2026-08-26 19:16:45.040751411 +0000 +@@ -151,6 +151,7 @@ + + ```text + NEUROFORGE_CONTROLLED_LEARNING=true ++NEUROFORGE_GOAL_LEARNING_ENABLED=false + OUTCOME_LEARNING_ENABLED=true + OUTCOME_LEARNING_FAIL_OPEN=false + NEUROFORGE_RESEARCH_ENABLED=false +@@ -159,3 +160,18 @@ + ``` + + Research anschließend gezielt aktivieren, beobachten und erst danach – falls gewünscht – Autonomy einschalten. ++ ++ ++## Goal-Learning als separate Freigabe (v1.4.1) ++ ++`NEUROFORGE_CONTROLLED_LEARNING=true` deaktiviert weiterhin rohes Chat-/Assistant-Lernen. ++Goal-Cycles besitzen nun einen eigenen Schalter: ++ ++```env ++NEUROFORGE_CONTROLLED_LEARNING=true ++NEUROFORGE_GOAL_LEARNING_ENABLED=true ++``` ++ ++Damit dürfen `RunGoalCycle` und autonome Goals semantische `goal-cycle`-Memories erzeugen, ++ohne `LearnChatInputs`, `LearnChatResponses` oder `AllowImports` wieder zu aktivieren. ++Für autonome Research-Goals sind zusätzlich die jeweiligen Research-/Autonomy-Schalter nötig. +diff -ruN '--exclude=patches' /mnt/data/_inspect140/glpi-neuroforge-mega-v1.4.0-gitea-envfix/platform/neuroforge/cmd/server/main.go /mnt/data/glpi-neuroforge-mega-v1.4.1-gitea/platform/neuroforge/cmd/server/main.go +--- /mnt/data/_inspect140/glpi-neuroforge-mega-v1.4.0-gitea-envfix/platform/neuroforge/cmd/server/main.go 2026-08-25 19:00:18.000000000 +0000 ++++ /mnt/data/glpi-neuroforge-mega-v1.4.1-gitea/platform/neuroforge/cmd/server/main.go 2026-08-26 19:16:45.039341672 +0000 +@@ -144,6 +144,19 @@ + return fmt.Errorf("apply controlled learning bootstrap: %w", err) + } + } ++ // Goal-cycle learning is an independent trust boundary. Controlled learning ++ // keeps it disabled by default, but operators may explicitly enable it ++ // without re-enabling raw chat/input learning or memory imports. Apply this ++ // override after the controlled-learning bootstrap so the explicit setting ++ // wins on every restart. ++ if v, ok := envBool("NEUROFORGE_GOAL_LEARNING_ENABLED"); ok { ++ cfg := s.Config() ++ cfg.Brain.LearningPolicy.LearnGoalCycles = v ++ if err := s.UpdateConfig(cfg); err != nil { ++ return fmt.Errorf("apply goal learning environment bootstrap: %w", err) ++ } ++ } ++ + if _, hasResearch := os.LookupEnv("NEUROFORGE_RESEARCH_ENABLED"); hasResearch { + cfg := s.Config() + if v, ok := envBool("NEUROFORGE_RESEARCH_ENABLED"); ok { +diff -ruN '--exclude=patches' /mnt/data/_inspect140/glpi-neuroforge-mega-v1.4.0-gitea-envfix/services/control/main.go /mnt/data/glpi-neuroforge-mega-v1.4.1-gitea/services/control/main.go +--- /mnt/data/_inspect140/glpi-neuroforge-mega-v1.4.0-gitea-envfix/services/control/main.go 2026-08-26 15:17:10.000000000 +0000 ++++ /mnt/data/glpi-neuroforge-mega-v1.4.1-gitea/services/control/main.go 2026-08-26 19:16:45.040515305 +0000 +@@ -50,6 +50,7 @@ + neuroforgeSearchK string + failOpen string + controlledLearning string ++ goalLearning string + outcomeLearning string + outcomeRetrieval string + outcomeSearchK string +@@ -75,7 +76,7 @@ + if nfKeyRaw != "" { + nfAuth = "Bearer " + nfKeyRaw + } +- s := &server{http: &http.Client{Timeout: 6 * time.Second}, agentURL: strings.TrimRight(agentURL, "/"), agentReadToken: strings.TrimSpace(os.Getenv("CONTROL_READ_TOKEN")), neuroforgeURL: strings.TrimRight(nfURL, "/"), neuroforgeKey: nfKeyRaw, codebaseMemoryURL: strings.TrimRight(strings.TrimSpace(os.Getenv("CODEBASE_MEMORY_URL")), "/"), codebaseMemoryPublicURL: strings.TrimRight(strings.TrimSpace(os.Getenv("PUBLIC_CODEBASE_MEMORY_URL")), "/"), vectorMode: env("KNOWLEDGE_VECTOR_BACKEND", "dual"), neuroforgeSearchK: env("NEUROFORGE_SEARCH_K", "128"), failOpen: env("NEUROFORGE_FAIL_OPEN", "true"), controlledLearning: env("NEUROFORGE_CONTROLLED_LEARNING", "true"), outcomeLearning: env("OUTCOME_LEARNING_ENABLED", "true"), outcomeRetrieval: env("OUTCOME_RETRIEVAL_ENABLED", "true"), outcomeSearchK: env("OUTCOME_RETRIEVAL_SEARCH_K", "6"), outcomeMinSimilarity: env("OUTCOME_RETRIEVAL_MIN_SIMILARITY", "0.58"), outcomeFailOpen: env("OUTCOME_RETRIEVAL_FAIL_OPEN", "true"), researchEnabled: env("NEUROFORGE_RESEARCH_ENABLED", "false"), searxngEnabled: env("NEUROFORGE_SEARXNG_ENABLED", "false"), autonomyEnabled: env("NEUROFORGE_AUTONOMY_ENABLED", "false")} ++ s := &server{http: &http.Client{Timeout: 6 * time.Second}, agentURL: strings.TrimRight(agentURL, "/"), agentReadToken: strings.TrimSpace(os.Getenv("CONTROL_READ_TOKEN")), neuroforgeURL: strings.TrimRight(nfURL, "/"), neuroforgeKey: nfKeyRaw, codebaseMemoryURL: strings.TrimRight(strings.TrimSpace(os.Getenv("CODEBASE_MEMORY_URL")), "/"), codebaseMemoryPublicURL: strings.TrimRight(strings.TrimSpace(os.Getenv("PUBLIC_CODEBASE_MEMORY_URL")), "/"), vectorMode: env("KNOWLEDGE_VECTOR_BACKEND", "dual"), neuroforgeSearchK: env("NEUROFORGE_SEARCH_K", "128"), failOpen: env("NEUROFORGE_FAIL_OPEN", "true"), controlledLearning: env("NEUROFORGE_CONTROLLED_LEARNING", "true"), goalLearning: env("NEUROFORGE_GOAL_LEARNING_ENABLED", "false"), outcomeLearning: env("OUTCOME_LEARNING_ENABLED", "true"), outcomeRetrieval: env("OUTCOME_RETRIEVAL_ENABLED", "true"), outcomeSearchK: env("OUTCOME_RETRIEVAL_SEARCH_K", "6"), outcomeMinSimilarity: env("OUTCOME_RETRIEVAL_MIN_SIMILARITY", "0.58"), outcomeFailOpen: env("OUTCOME_RETRIEVAL_FAIL_OPEN", "true"), researchEnabled: env("NEUROFORGE_RESEARCH_ENABLED", "false"), searxngEnabled: env("NEUROFORGE_SEARXNG_ENABLED", "false"), autonomyEnabled: env("NEUROFORGE_AUTONOMY_ENABLED", "false")} + s.targets = []target{ + {ID: "agent", Name: "GLPI AI Agent", URL: agentURL, PublicURL: env("PUBLIC_AGENT_URL", "http://localhost:8080"), Path: "/readyz"}, + {ID: "knowledge", Name: "Knowledgebase", URL: env("KNOWLEDGE_URL", "http://knowledge:8080"), PublicURL: env("PUBLIC_KNOWLEDGE_URL", "http://localhost:8081"), Path: "/api/health"}, +@@ -123,7 +124,7 @@ + } + + func (s *server) handleConfig(w http.ResponseWriter, r *http.Request) { +- writeJSON(w, 200, map[string]any{"vector_backend": s.vectorMode, "neuroforge_search_k": s.neuroforgeSearchK, "neuroforge_fail_open": s.failOpen, "controlled_learning": s.controlledLearning, "outcome_learning": s.outcomeLearning, "outcome_retrieval": s.outcomeRetrieval, "outcome_retrieval_search_k": s.outcomeSearchK, "outcome_retrieval_min_similarity": s.outcomeMinSimilarity, "outcome_retrieval_fail_open": s.outcomeFailOpen, "quality_replay": "available-on-agent", "research_enabled": s.researchEnabled, "searxng_enabled": s.searxngEnabled, "autonomy_enabled": s.autonomyEnabled, "control_plane": "read-only", "policy_owner": "glpi-agent", "unified_graph": true, "engineering_graph": "embedded-ast", "codebase_memory_url": s.codebaseMemoryPublicURL}) ++ writeJSON(w, 200, map[string]any{"vector_backend": s.vectorMode, "neuroforge_search_k": s.neuroforgeSearchK, "neuroforge_fail_open": s.failOpen, "controlled_learning": s.controlledLearning, "goal_learning": s.goalLearning, "outcome_learning": s.outcomeLearning, "outcome_retrieval": s.outcomeRetrieval, "outcome_retrieval_search_k": s.outcomeSearchK, "outcome_retrieval_min_similarity": s.outcomeMinSimilarity, "outcome_retrieval_fail_open": s.outcomeFailOpen, "quality_replay": "available-on-agent", "research_enabled": s.researchEnabled, "searxng_enabled": s.searxngEnabled, "autonomy_enabled": s.autonomyEnabled, "control_plane": "read-only", "policy_owner": "glpi-agent", "unified_graph": true, "engineering_graph": "embedded-ast", "codebase_memory_url": s.codebaseMemoryPublicURL}) + } + + func (s *server) handleStatus(w http.ResponseWriter, r *http.Request) { diff --git a/platform/neuroforge/Dockerfile b/platform/neuroforge/Dockerfile index b545668..033bf91 100644 --- a/platform/neuroforge/Dockerfile +++ b/platform/neuroforge/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.26-alpine AS build +FROM golang:1.23-alpine AS build WORKDIR /src COPY go.mod ./ COPY cmd ./cmd @@ -7,7 +7,7 @@ RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/neuroforge ./cmd/s CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/neuroforge-worker ./cmd/worker && \ CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/neuroforge-bench ./cmd/bench -FROM alpine:3.24 AS server +FROM alpine:3.21 AS server RUN apk add --no-cache ca-certificates poppler-utils && \ addgroup -S neuroforge && adduser -S -G neuroforge neuroforge && \ mkdir -p /app/data && chown -R neuroforge:neuroforge /app @@ -19,7 +19,7 @@ EXPOSE 8080 HEALTHCHECK --interval=15s --timeout=3s --start-period=10s --retries=4 CMD wget -q -O - http://127.0.0.1:8080/readyz >/dev/null || exit 1 ENTRYPOINT ["neuroforge", "-data", "/app/data", "-listen", ":8080"] -FROM alpine:3.24 AS worker +FROM alpine:3.21 AS worker RUN apk add --no-cache ca-certificates && addgroup -S neuroforge && adduser -S -G neuroforge neuroforge COPY --from=build /out/neuroforge-worker /usr/local/bin/neuroforge-worker USER neuroforge diff --git a/platform/neuroforge/cmd/server/main.go b/platform/neuroforge/cmd/server/main.go index 13c10be..6c10acc 100644 --- a/platform/neuroforge/cmd/server/main.go +++ b/platform/neuroforge/cmd/server/main.go @@ -144,6 +144,19 @@ func run() (retErr error) { return fmt.Errorf("apply controlled learning bootstrap: %w", err) } } + // Goal-cycle learning is an independent trust boundary. Controlled learning + // keeps it disabled by default, but operators may explicitly enable it + // without re-enabling raw chat/input learning or memory imports. Apply this + // override after the controlled-learning bootstrap so the explicit setting + // wins on every restart. + if v, ok := envBool("NEUROFORGE_GOAL_LEARNING_ENABLED"); ok { + cfg := s.Config() + cfg.Brain.LearningPolicy.LearnGoalCycles = v + if err := s.UpdateConfig(cfg); err != nil { + return fmt.Errorf("apply goal learning environment bootstrap: %w", err) + } + } + if _, hasResearch := os.LookupEnv("NEUROFORGE_RESEARCH_ENABLED"); hasResearch { cfg := s.Config() if v, ok := envBool("NEUROFORGE_RESEARCH_ENABLED"); ok { diff --git a/platform/neuroforge/go.mod b/platform/neuroforge/go.mod index 9aa6220..41ef308 100644 --- a/platform/neuroforge/go.mod +++ b/platform/neuroforge/go.mod @@ -1,3 +1,3 @@ module neuroforge -go 1.26 +go 1.23 diff --git a/scripts/generate-secrets.sh b/scripts/generate-secrets.sh index 854c05b..0d36db0 100644 --- a/scripts/generate-secrets.sh +++ b/scripts/generate-secrets.sh @@ -1,7 +1,10 @@ #!/bin/sh set -eu + gen() { openssl rand -hex 32; } + cat <