This commit is contained in:
pporcheret
2026-10-30 22:10:03 +01:00
parent 7f26f9b015
commit 90ffa635a0
161 changed files with 19042 additions and 111 deletions
+12 -17
View File
@@ -1,6 +1,7 @@
"""Identity editor and current assistant name, authenticated by Alfred's admin UI.
Identity text stays in config/identity.md. All writes are atomic; dated revisions
Identity is stored natively in Hermes SOUL.md, not injected into questions.
All writes are atomic; dated revisions
are kept separately. Technical names/paths/API identifiers are never renamed.
"""
from __future__ import annotations
@@ -19,7 +20,7 @@ from services import admin_console
ROOT = Path(__file__).resolve().parents[1]
CONFIG = ROOT / 'config'
IDENTITY = CONFIG / 'identity.md'
IDENTITY = Path('/root/.hermes/SOUL.md')
TRACKER = CONFIG / 'identity_name_state.json'
HISTORY = CONFIG / 'identity_history'
LOCK = threading.RLock()
@@ -33,12 +34,10 @@ def active_name():
def identity_path():
# Avoid an admin Web editor writing outside the identity config directory.
raw = Path(os.getenv('ALFRED_IDENTITY_FILE', str(IDENTITY))).expanduser()
resolved = raw.resolve()
if resolved.parent != CONFIG.resolve() or raw.is_symlink():
raise ValueError('Le fichier ALFRED_IDENTITY_FILE est externe à config/ : édition Web refusée.')
return resolved
# No arbitrary paths from env or web; this editor controls one fixed Hermes file.
if IDENTITY.is_symlink():
raise ValueError('SOUL.md ne doit pas être un lien symbolique.')
return IDENTITY
def sha(text):
@@ -115,7 +114,7 @@ def sync_identity_name(name=None):
original = _read_text()
if not original.strip():
# No identity installed: don't silently create a new persona.
raise ValueError('Le fichier identity.md est vide ou absent.')
raise ValueError('Le fichier SOUL.md est vide ou absent.')
old = _old_name(original)
updated = _replace_persona_name(original, old, new)
if updated != original:
@@ -129,7 +128,7 @@ def sync_identity_name(name=None):
def identity_for_hermes(text):
"""Runtime guard: current name wins even if a legacy identity wasn't synced."""
"""Legacy compatibility only. No longer used to build user prompts."""
new = active_name()
old = _old_name(text)
content = _replace_persona_name(text, old, new) if text else text
@@ -161,7 +160,7 @@ def register_identity_page(app):
except (OSError, ValueError) as e:
return jsonify(error=str(e)), 503
res = jsonify(name=active_name(), text=content, revision=sha(content),
file='config/identity.md')
file='/root/.hermes/SOUL.md')
res.headers['Cache-Control'] = 'no-store, private'
return res
@@ -190,15 +189,11 @@ def register_identity_page(app):
mode = (path.stat().st_mode & 0o777) if path.exists() else 0o600
_save_atomic(path, text, mode)
res = jsonify(ok=True, revision=sha(text), name=active_name(),
updated=text != old, file='config/identity.md')
updated=text != old, file='/root/.hermes/SOUL.md')
res.headers['Cache-Control'] = 'no-store, private'
return res
except (OSError, ValueError) as e:
return jsonify(error='Enregistrement impossible : '+str(e)), 500
app.register_blueprint(bp)
# If a renamed assistant was configured before installation, reconcile on startup.
try:
sync_identity_name()
except (OSError, ValueError) as e:
app.logger.warning('Synchronisation identité différée : %s', e)
# No startup rewrite: keep manually edited SOUL.md intact.