2025-10-19 21:54:29 +08:00
;;; ai.el -*- lexical-binding: t; -*-
2025-10-19 22:16:22 +08:00
;;; ============================================================================
;;; gptel Configuration
;;; ============================================================================
;; Core gptel setup
( use-package! gptel
2025-11-22 13:52:03 +08:00
:defer t
2025-10-19 22:16:22 +08:00
:config
;; Default backend: OpenRouter
( setq gptel-model 'google/gemini-2.5-flash
gptel-backend
( gptel-make-openai " OpenRouter "
:host " openrouter.ai "
:endpoint " /api/v1/chat/completions "
:stream t
:key " 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 "
:models ' ( google/gemini-2.5-flash
google/gemini-2.5-pro
anthropic/claude-sonnet-4
anthropic/claude-sonnet-4.5 ) ) )
;; Use org-mode by default for better note-taking
( setq gptel-default-mode 'org-mode )
;; Move cursor to end of response automatically
( add-hook 'gptel-post-response-functions 'gptel-end-of-response )
2025-11-07 01:26:43 +08:00
;; Keybindings - using SPC A for AI (uppercase to avoid conflicts)
2025-10-19 22:16:22 +08:00
( map! :leader
2025-11-07 01:26:43 +08:00
( :prefix ( " A " . " AI/gptel " )
2025-10-19 22:16:22 +08:00
:desc " gptel chat " " g " #' gptel
:desc " gptel send " " s " #' gptel-send
:desc " gptel menu " " m " #' gptel-menu
:desc " gptel rewrite " " r " #' gptel-rewrite
:desc " Add context " " c " #' gptel-add
:desc " Add file to context " " f " #' gptel-add-file ) )
;; Additional keybindings in gptel buffer
( map! :map gptel-mode-map
" C-c RET " #' gptel-send
" C-c C-k " #' gptel-abort
" C-c C-c " #' gptel-menu ) )
;; gptel presets for different tasks
( after! gptel
;; Coding assistant preset
( gptel-make-preset 'coder
:description " Expert coding assistant "
:backend " OpenRouter "
:model 'anthropic/claude-sonnet-4.5
:system " You are an expert coding assistant. Provide high-quality code solutions, refactorings, and explanations. Be concise but thorough. Include error handling and follow best practices. " )
;; Code explainer preset
( gptel-make-preset 'explain
:description " Explain code to beginners "
:system " Explain this code to a novice programmer. Use simple language and break down complex concepts. " )
;; Refactoring preset
( gptel-make-preset 'refactor
:description " Code refactoring expert "
:model 'anthropic/claude-sonnet-4.5
:system " You are a code refactoring expert. Improve code quality, readability, and performance while maintaining functionality. Explain your changes. " )
;; Quick answers preset
( gptel-make-preset 'quick
:description " Quick, concise answers "
:model 'google/gemini-2.5-flash
:system " Provide quick, concise answers. Be direct and to the point. " )
;; Documentation writer preset
( gptel-make-preset 'docs
:description " Documentation writer "
:system " Write clear, comprehensive documentation. Include examples and explain edge cases. " ) )
;;; ============================================================================
;;; gptel-quick - Quick lookups and explanations
;;; ============================================================================
( use-package! gptel-quick
:after gptel
2025-11-22 13:52:03 +08:00
:defer t
2025-10-19 22:16:22 +08:00
:config
;; Include context from gptel-add if available
( setq gptel-quick-use-context t )
( map! :leader
2025-11-07 01:26:43 +08:00
( :prefix " A "
2025-10-19 22:16:22 +08:00
:desc " Quick lookup " " q " #' gptel-quick ) ) )
;;; ============================================================================
;;; gptel-extensions - Extra utility functions
;;; ============================================================================
( use-package! gptel-extensions
:after gptel
2025-11-22 13:52:03 +08:00
:defer t
2025-10-19 22:16:22 +08:00
:config
( map! :leader
2025-11-07 01:26:43 +08:00
( :prefix " A "
2025-10-19 22:16:22 +08:00
:desc " Load buffer into session " " l " #' gptel-extensions-load-buffer
:desc " Send whole buffer " " b " #' gptel-extensions-send-whole-buffer
:desc " Refactor region " " R " #' gptel-extensions-refactor ) ) )
;;; ============================================================================
;;; gptel-autocomplete - Inline code completion
;;; ============================================================================
( use-package! gptel-autocomplete
:after gptel
2025-11-22 13:52:03 +08:00
:defer t
2025-11-07 01:26:43 +08:00
:commands ( gptel-complete gptel-accept-completion )
2025-10-19 22:16:22 +08:00
:config
2025-11-07 01:26:43 +08:00
;; Configure context size
( setq gptel-autocomplete-before-context-lines 100
gptel-autocomplete-after-context-lines 20
gptel-autocomplete-temperature 0.1 )
2025-10-19 22:16:22 +08:00
2025-11-07 01:26:43 +08:00
;; Keybindings for autocomplete
( map! :leader
( :prefix " A "
:desc " Complete at point " " C " #' gptel-complete
:desc " Accept completion " " a " #' gptel-accept-completion ) )
2025-10-19 22:16:22 +08:00
2025-11-07 01:26:43 +08:00
;; Also add convenient keybindings in prog-mode
( map! :map prog-mode-map
" M-TAB " #' gptel-complete
" C-c TAB " #' gptel-complete
" C-c C-a " #' gptel-accept-completion ) )
2025-10-19 22:16:22 +08:00
;;; ============================================================================
;;; Optional: Add Ollama for local models (commented out by default)
;;; ============================================================================
;; Uncomment to add Ollama support for local models
;; (after! gptel
;; (gptel-make-ollama "Ollama"
;; :host "localhost:11434"
;; :stream t
;; :models '(qwen2.5-coder:latest
;; mistral:latest
;; llama3.2:latest)))
;; To make Ollama default, uncomment:
;; (setq gptel-model 'qwen2.5-coder:latest
;; gptel-backend (gptel-make-ollama "Ollama"
;; :host "localhost:11434"
;; :stream t
;; :models '(qwen2.5-coder:latest
;; mistral:latest)))
;;; ============================================================================
;;; Helper functions
;;; ============================================================================
( defun my/gptel-quick-explain-region ( )
" Quickly explain selected code region. "
( interactive )
( when ( use-region-p )
( let ( ( code ( buffer-substring-no-properties ( region-beginning ) ( region-end ) ) ) )
( gptel-request code
:system " Explain this code concisely in 2-3 sentences. "
:callback ( lambda ( response info )
( message " Explanation: %s " response ) ) ) ) ) )
( defun my/gptel-proofread-region ( )
" Proofread and improve selected text. "
( interactive )
( when ( use-region-p )
( gptel-rewrite-region ( region-beginning ) ( region-end )
" Fix spelling, grammar, and improve clarity. Keep the same tone and style. " ) ) )
;; Add keybindings for helper functions
( map! :leader
2025-11-07 01:26:43 +08:00
( :prefix " A "
2025-10-19 22:16:22 +08:00
:desc " Quick explain " " e " #' my/gptel-quick-explain-region
:desc " Proofread text " " p " #' my/gptel-proofread-region ) )
2025-10-19 21:57:36 +08:00
;;; Claude Code Configuration
( use-package! claude-code
2025-11-22 13:52:03 +08:00
:defer t
2025-10-19 21:57:36 +08:00
:config
;; Use vterm backend
( setq claude-code-terminal-backend 'vterm )
;; Enable global mode
( claude-code-mode 1 )
;; Set key bindings prefix
( map! :leader
( :prefix ( " C " . " claude-code " )
:desc " Start Claude " " c " #' claude-code
:desc " Start in directory " " d " #' claude-code-start-in-directory
:desc " Continue conversation " " C " #' claude-code-continue
:desc " Resume session " " R " #' claude-code-resume
:desc " New instance " " i " #' claude-code-new-instance
:desc " Kill Claude " " k " #' claude-code-kill
:desc " Kill all instances " " K " #' claude-code-kill-all
:desc " Send command " " s " #' claude-code-send-command
:desc " Send command with context " " x " #' claude-code-send-command-with-context
:desc " Send region/buffer " " r " #' claude-code-send-region
:desc " Send buffer file " " o " #' claude-code-send-buffer-file
:desc " Fix error at point " " e " #' claude-code-fix-error-at-point
:desc " Toggle window " " t " #' claude-code-toggle
:desc " Switch to buffer " " b " #' claude-code-switch-to-buffer
:desc " Select buffer " " B " #' claude-code-select-buffer
:desc " Toggle read-only " " z " #' claude-code-toggle-read-only-mode
:desc " Cycle mode " " M " #' claude-code-cycle-mode
:desc " Transient menu " " m " #' claude-code-transient
:desc " Slash commands " " / " #' claude-code-slash-commands
:desc " Fork conversation " " f " #' claude-code-fork
:desc " Send return " " y " #' claude-code-send-return
:desc " Send escape " " n " #' claude-code-send-escape
:desc " Send 1 " " 1 " #' claude-code-send-1
:desc " Send 2 " " 2 " #' claude-code-send-2
:desc " Send 3 " " 3 " #' claude-code-send-3 ) )
;; Optional: Configure window display (side window on right)
( add-to-list 'display-buffer-alist
' ( " ^ \\ *claude "
( display-buffer-in-side-window )
( side . right )
( window-width . 90 ) ) )
;; Optional: Enable auto-revert for files modified by Claude
( global-auto-revert-mode 1 )
;; Optional: Increase vterm scrollback for long conversations
( add-hook 'claude-code-start-hook
( lambda ( )
( when ( eq claude-code-terminal-backend 'vterm )
( setq-local vterm-max-scrollback 100000 ) ) ) ) )