;;; -*- lexical-binding: t; -*- ;;; Commentary: ;;; Code: (require 'fill-column) (use-package rcirc :bind (:map rcirc-mode-map ("C-c j" . #'bd/rcirc-jump-net) ("C-c q" . #'bd/rcirc-detach-buffer)) :hook ((rcirc-mode . (lambda () (setq-local fill-column-desired-width 80) (fill-column-mode) (rcirc-omit-mode)))) :config (setopt bd/rcirc-networks '("libera" "furnet")) (defun bd/rcirc-jump-net () "Prompts the user for a irc network in BD/RCIRC-NETWORKS, then issues ZNC to hop networks." (interactive) (let ((buffer (current-buffer))) (when (and (buffer-local-value 'rcirc-server-buffer buffer) (eq (process-status (rcirc-buffer-process)) 'open)) (let ((target (completing-read "Jump to: " bd/rcirc-networks))) (if (stringp target) (rcirc-send-string (rcirc-buffer-process) "PRIVMSG" "*status" : (concat "JUMPNETWORK " target))))))) (defun bd/rcirc-detach-buffer () "If the current buffer is an rcirc channel, detaches through ZNC and deletes the buffer. This bypasses the default behavior of deleting an active channel, which is issuing the PART command." (interactive) (let ((buffer (current-buffer))) (when (and (rcirc-buffer-process) (eq (process-status (rcirc-buffer-process)) 'open)) (with-rcirc-server-buffer (setq rcirc-buffer-alist (rassq-delete-all buffer rcirc-buffer-alist))) (rcirc-update-short-buffer-names) (if (rcirc-channel-p rcirc-target) (rcirc-send-string (rcirc-buffer-process) "PRIVMSG" "*status" : (concat "DETACH " rcirc-target)))) (setq rcirc-target nil) (kill-buffer buffer))) (setopt rcirc-fill-column 80 rcirc-omit-threshold 10 rcirc-reconnect-delay 60 rcirc-omit-responses '("JOIN" "PART" "QUIT" "NICK" "AWAY") rcirc-track-minor-mode t rcirc-track-ignore-server-buffer-flag t rcirc-server-alist '(("operationnull.com" :nick "Gondul" :user-name "Gondul" :port 6697 :encryption tls)))) (use-package gptel :bind (("C-c g" . gptel-menu) ("C-c C-t" . (lambda () (interactive) (gptel "*evka*") (switch-to-buffer "*evka*")))) :config (defvar bd/llama-cpp-buffer-name "*llama-cpp-proc*") (defvar bd/llama-cpp-reasoning-buffer-name "*llama-cpp-reasoning*") (defvar bd/llama-cpp-port "4568") (defvar bd/llama-cpp-threads "8") (defvar bd/llama-cpp-model-file "Qwen3-4B.Q5_K_M.gguf") ;; most models seem to ignore this, or llama-cpp doesn't add /no_think like it's supposed to (defvar bd/llama-cpp-reasoning-budget nil) (defun bd/gptel-start-backend () (interactive) (let ((process (get-buffer-process bd/llama-cpp-buffer-name))) (if process (message "llama-cpp process is already running!") (progn (start-process-shell-command "llama-cpp" bd/llama-cpp-buffer-name (concat "llama-server --reasoning-budget " (if bd/llama-cpp-reasoning-budget "-1" "0") " --port " bd/llama-cpp-port " -t " bd/llama-cpp-threads " -m " (expand-file-name bd/llama-cpp-model-file "~/.config/guix/assets/")))) (unless (get-buffer bd/llama-cpp-reasoning-buffer-name) (generate-new-buffer bd/llama-cpp-reasoning-buffer-name))))) (defun bd/gptel-stop-backend () (interactive) (let ((process (get-buffer-process bd/llama-cpp-buffer-name))) (if process (progn (delete-process process) (kill-buffer bd/llama-cpp-buffer-name) (message "Killed %s." process)) (message "No llama-cpp process is running.")))) (defun bd/gptel-restart-backend () (interactive) (bd/gptel-stop-backend) (bd/gptel-start-backend)) (bd/gptel-start-backend) (add-to-list 'gptel-directives '(evka . "You are a wolf (furry) named Evka hired as a secretary to complete language-based tasks. First describe an action your character does, e.x.: *I tap my claws on the desk*. Finish by responding to the task as tersely as possible, in character./no_think")) (setopt gptel-model 'qwen-4b gptel-backend (gptel-make-openai "llama-cpp" :stream t :protocol "http" :host (concat "localhost:" bd/llama-cpp-port) :models '(qwen-4b)) gptel-max-tokens 500 gptel--system-message (alist-get 'evka gptel-directives) gptel-include-reasoning bd/llama-cpp-reasoning-buffer-name)) (provide 'bd--chat) ;;; bd--chat.el ends here