Files
memex/notes/skill-web-research.org

3.2 KiB

Web Research Skill (Generalized)

This skill provides the agent with internet connectivity via multiple pluggable browser engines.

Trigger

(defun trigger-skill-web-research (context)
  (let ((type (getf context :type))
        (payload (getf context :payload)))
    (and (eq type :EVENT)
         (eq (getf payload :sensor) :delegation)
         (eq (getf payload :target-skill) :web))))

Browser Engines

We define multiple backends for fetching web content.

(defun fetch-with-lynx (url)
  "Engine: Lynx. Best for fast text extraction from blogs/docs."
  (let ((cmd (format nil "lynx -dump -nolist '~a'" url)))
    (uiop:run-program cmd :output :string :ignore-error-status t)))

(defun fetch-with-curl (url)
  "Engine: Curl. Best for raw HTML or API inspection."
  (let ((cmd (format nil "curl -sL '~a'" url)))
    (uiop:run-program cmd :output :string :ignore-error-status t)))

(defun fetch-with-playwright (url)
  "Engine: Playwright (Placeholder). In the future, this calls a Python bridge."
  (format nil "ERROR: Playwright engine not yet implemented. Falling back to Lynx...~%~a" 
          (fetch-with-lynx url)))

(defun web-fetch (url &optional engine)
  "Dispatch the fetch request to the specified engine (defaults to Lynx)."
  (case engine
    (:lynx (fetch-with-lynx url))
    (:curl (fetch-with-curl url))
    (:playwright (fetch-with-playwright url))
    (t (fetch-with-lynx url))))

Neuro Prompt

System 1 chooses the engine based on the task complexity.

(defun neuro-skill-web-research (context)
  (let* ((payload (getf context :payload))
         (query (getf payload :query))
         ;; The LLM can specify an engine. If not, we default to Lynx.
         (requested-engine (or (getf payload :engine) :lynx))
         (is-url (or (search "http://" query) (search "https://" query)))
         (target-url (if is-url 
                         query 
                         (format nil "https://duckduckgo.com/html/?q=~a" query)))
         (web-text (web-fetch target-url requested-engine)))
    
    (let ((curated (if (and web-text (> (length web-text) 5000))
                       (format nil "~a... [TRUNCATED]" (subseq web-text 0 5000))
                       (or web-text "No content fetched."))))
      
      (format nil "
        You are the Web Research synthesizer.
        USER QUERY - '~a'
        ENGINE USED - ~a
        TARGET URL - ~a
        
        RAW CONTENT FETCHED -
        ---
        ~a
        ---
        
        Synthesize a concise, factual answer. 
        Return a Lisp plist - (:target :emacs :action :message :text \"your summary\")
      " query requested-engine target-url curated))))

Symbolic Verification

(defun verify-skill-web-research (proposed-action context)
  (if (eq (getf proposed-action :action) :message)
      proposed-action
      '(:target :emacs :action :message :text "Web skill failed to synthesize message.")))

Registration

(defskill :skill-web-research
  :priority 80
  :trigger #'trigger-skill-web-research
  :neuro #'neuro-skill-web-research
  :symbolic #'verify-skill-web-research)