refactor: moved org-agent to its own repository as a submodule
This commit is contained in:
85
notes/skill-emacs-bridge.org
Normal file
85
notes/skill-emacs-bridge.org
Normal file
@@ -0,0 +1,85 @@
|
||||
#+TITLE - Emacs Actuator Bridge Skill
|
||||
#+AUTHOR - org-agent
|
||||
#+SKILL_NAME - skill-emacs-bridge
|
||||
|
||||
This skill provides the sensor (TCP Socket) and actuator (OACP Dispatch) for the Emacs interface. It abstracts the I/O layer away from the core `org-agent` kernel.
|
||||
|
||||
* Sensor & State (TCP Socket Listener)
|
||||
We start a TCP server that listens for incoming connections from `org-agent.el`.
|
||||
|
||||
#+begin_src lisp
|
||||
(defvar *emacs-server-thread* nil)
|
||||
(defvar *emacs-server-socket* nil)
|
||||
(defvar *active-emacs-clients* nil "List of active Emacs socket streams.")
|
||||
(defvar *emacs-clients-lock* (bt:make-lock "emacs-clients-lock"))
|
||||
|
||||
(defun handle-emacs-client (stream)
|
||||
"Handle a single OACP connection from Emacs."
|
||||
(bt:with-lock-held (*emacs-clients-lock*)
|
||||
(push stream *active-emacs-clients*))
|
||||
(unwind-protect
|
||||
(handler-case
|
||||
(loop
|
||||
(let* ((len-buf (make-string 6))
|
||||
(read-len (read-sequence len-buf stream)))
|
||||
(when (zerop read-len) (return))
|
||||
(let* ((msg-len (parse-integer len-buf :radix 16))
|
||||
(msg-buf (make-string msg-len)))
|
||||
(read-sequence msg-buf stream)
|
||||
(let ((plist (read-from-string msg-buf)))
|
||||
(org-agent:kernel-log "BRIDGE: Received message type ~a" (getf plist :type))
|
||||
;; PROCESS: Send the message through the 4-stage cognitive loop
|
||||
(org-agent:cognitive-loop plist)))))
|
||||
(error (c) (org-agent:kernel-log "BRIDGE ERROR: ~a" c)))
|
||||
(bt:with-lock-held (*emacs-clients-lock*)
|
||||
(setf *active-emacs-clients* (remove stream *active-emacs-clients*)))
|
||||
(close stream)))
|
||||
|
||||
(defun start-emacs-server (&key (port 9105))
|
||||
"Start the OACP listener for Emacs."
|
||||
(setf *emacs-server-socket* (usocket:socket-listen "0.0.0.0" port :reuse-address t))
|
||||
(setf *emacs-server-thread*
|
||||
(bt:make-thread
|
||||
(lambda ()
|
||||
(loop
|
||||
(let ((conn (usocket:socket-accept *emacs-server-socket*)))
|
||||
(bt:make-thread (lambda () (handle-emacs-client (usocket:socket-stream conn)))
|
||||
:name "org-agent-emacs-handler"))))
|
||||
:name "org-agent-emacs-daemon"))
|
||||
(org-agent:kernel-log "BRIDGE: Listening on port ~a" port))
|
||||
#+end_src
|
||||
|
||||
* Actuator (Outbound Dispatcher)
|
||||
When the core `cognitive-loop` decides on an action targeting `:emacs`, it delegates to this function.
|
||||
|
||||
#+begin_src lisp
|
||||
(defun broadcast-to-emacs (action-plist)
|
||||
"Translate an action into OACP framing and send to all connected Emacs clients."
|
||||
(let ((action-msg (org-agent:frame-message (prin1-to-string action-plist))))
|
||||
(bt:with-lock-held (*emacs-clients-lock*)
|
||||
(dolist (client *active-emacs-clients*)
|
||||
(ignore-errors
|
||||
(write-string action-msg client)
|
||||
(force-output client))))))
|
||||
#+end_src
|
||||
|
||||
* Skill Registration
|
||||
Register the skill. We don't use `trigger`, `neuro`, or `symbolic` because this is an I/O skill, not a cognitive skill. We just use the file evaluation to bootstrap the server and register the actuator.
|
||||
|
||||
#+begin_src lisp
|
||||
;; Register the actuator with the core Event Bus
|
||||
(org-agent:register-actuator :emacs #'broadcast-to-emacs)
|
||||
|
||||
;; Register as a skill so it appears on the dashboard
|
||||
(defskill :skill-emacs-bridge
|
||||
:priority 100
|
||||
:trigger (lambda (context) nil)
|
||||
:neuro (lambda (context) nil)
|
||||
:symbolic (lambda (action context) action))
|
||||
|
||||
;; Start the socket server when this skill is loaded by the daemon
|
||||
(let* ((env-port (uiop:getenv "ORG_AGENT_DAEMON_PORT"))
|
||||
(port (if env-port (parse-integer env-port :junk-allowed t) 9105)))
|
||||
(unless *emacs-server-thread*
|
||||
(start-emacs-server :port port)))
|
||||
#+end_src
|
||||
Reference in New Issue
Block a user