Files
passepartout/lisp/symbolic-identity.lisp
Amr Gharbeia e04b12c31c v0.8.0: TUI stabilization, command palette reverse-video highlight, hint bar redesign
- ROADMAP: consolidate all TUI work under v0.8.0 (removed premature
  v0.9.0/v0.10.x labels), restored original v0.9.0 eval harness plan
- channel-tui-view.org: Emacs-style reverse-video cursor (swap fg/bg
  instead of drawing █), hint bar now shows F:focus/MCP:count on left
  and token gauge + keybindings on right, sidebar reorganized to show
  GATE TRACE, RULES + BLOCK COUNT, COST, FILES panels
- channel-tui-main.org: command palette selection now uses reverse-video
  highlight (bg-input fg on input-fg bg, matching cursor style), fixed
  cond order so sel-p is checked before cat (all items had :category
  making sel-p unreachable), added session-cost extraction from daemon
- passepartout: export COLORTERM=truecolor for modern backend detection
2026-05-17 15:37:40 -04:00

93 lines
3.2 KiB
Common Lisp

(in-package :passepartout)
(defvar *agent-identity* ""
"Identity text loaded from ~/memex/IDENTITY.org at startup.
This variable holds the contents of the user's identity file.
Loaded by `load-identity-file` at daemon/skill initialization,
called from `agent-identity` for system prompt injection.
The file is user-editable and persists across restarts.
If the file is missing or empty, this variable remains \"\".")
(defun load-identity-file (&optional (path nil path-p))
"Load agent identity from an org file.
Reads the identity text file and caches it in
`*agent-identity*`. If PATH is not provided, defaults to
`~/memex/IDENTITY.org`.
Returns the file content string on success, or NIL if the file
does not exist or cannot be read."
(let* ((file-path (if path-p
(uiop:ensure-pathname path :ensure-absolute t)
(merge-pathnames "memex/IDENTITY.org"
(user-homedir-pathname)))))
(when (uiop:file-exists-p file-path)
(handler-case
(let ((content (uiop:read-file-string file-path)))
(setf *agent-identity* content)
content)
(error () nil)))))
(defun agent-identity ()
"Return the currently loaded agent identity string."
(or *agent-identity* ""))
;; Auto-load identity at skill init
(load-identity-file)
(defpackage :passepartout-identity-tests
(:use :common-lisp :fiveam :passepartout)
(:export :identity-suite))
(in-package :passepartout-identity-tests)
(def-suite identity-suite
:description "Agent identity loading and caching")
(in-suite identity-suite)
(test test-load-identity-file-returns-content
"Contract 1: load-identity-file reads an existing file, returns content."
(let* ((path "/tmp/memex-test-identity.org")
(content "### Personality
- Friendly
- Concise"))
(with-open-file (f path :direction :output :if-exists :supersede)
(write-string content f))
(unwind-protect
(let ((result (passepartout::load-identity-file path)))
(is (stringp result))
(is (search "Friendly" result))
(is (search "Concise" result)))
(ignore-errors (delete-file path)))))
(test test-load-identity-file-missing-nil
"Contract 1: nil when file does not exist."
(let ((result (passepartout::load-identity-file
"/tmp/memex-nonexistent-xxxx.org")))
(is (null result))))
(test test-agent-identity-cached
"Contract 2+3: agent-identity returns cached value after load."
(let* ((path "/tmp/memex-test-identity2.org")
(content "### Preferences
- Use shell cautiously"))
(with-open-file (f path :direction :output :if-exists :supersede)
(write-string content f))
(unwind-protect
(progn
(passepartout::load-identity-file path)
(let ((id (passepartout::agent-identity)))
(is (search "shell cautiously" id))))
(ignore-errors (delete-file path)))))
(test test-agent-identity-empty-default
"Contract 2: returns empty string when nothing was loaded."
(let ((prev passepartout::*agent-identity*))
(unwind-protect
(progn
(setf passepartout::*agent-identity* nil)
(is (string= "" (passepartout::agent-identity))))
(setf passepartout::*agent-identity* prev))))