Skip to content

A lightweight Lua chat plugin for Neovim with AI integration.

License

Notifications You must be signed in to change notification settings

wsdjeg/chat.nvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

136 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

chat.nvim

A lightweight, extensible chat plugin for Neovim with AI integration. Chat with AI assistants directly in your editor using a clean, floating window interface.

GitHub License GitHub Issues or Pull Requests GitHub commit activity GitHub Release luarocks

chat.nvim

✨ Features

  • Multiple AI Providers: Built-in support for DeepSeek, GitHub AI, Moonshot, OpenRouter, Qwen, SiliconFlow, Tencent, and more
  • Custom Provider Support: Easily add your own AI providers via Lua modules
  • Tool Call Integration: Built-in tools for file operations (@read_file, @find_files) with custom tool support
  • Floating Window Interface: Clean, non-intrusive chat interface
  • Session Management: Run multiple parallel sessions with independent AI models, each maintaining separate conversation histories and configurations
  • Picker Integration: Seamless integration with picker.nvim
  • Streaming Responses: Real-time AI responses with cancellation support
  • Lightweight: Pure Lua implementation with minimal dependencies

📦 Installation

Using nvim-plug:

require('plug').add({
  {
    'wsdjeg/chat.nvim',
    depends = { {
      'wsdjeg/job.nvim',
    } },
    opt = {
      provider = 'deepseek',
      api_key = {
        deepseek = 'xxxxx',
        github = 'xxxxx',
      },
      width = 0.8, -- 80% of vim.o.columns
      height = 0.8, -- 80% of vim.o.lines
      border = 'rounded',
      -- default allowed_path is empty string, which means no files is allowed.
      -- this also can be a table of string.
      allowed_path = '',
    },
  },
})

⚙️ Usage

chat.nvim provides several commands to manage your AI conversations. The main command is :Chat, which opens the chat window. You can also navigate between sessions using the following commands.

Basic Commands

Command Description
:Chat Open the chat window with the current session
:Chat new Start a new chat session
:Chat prev Switch to the previous chat session
:Chat next Switch to the next chat session
:Chat delete Delete current session and create new empty session
:Chat clear Clear all messages in current session
:Chat cd <dir> Change current session cwd, open chat window

Parallel Sessions

chat.nvim supports running multiple chat sessions simultaneously, with each session operating independently:

  • Independent Model Selection: Each session can use a different AI model (e.g., Session A with DeepSeek, Session B with GitHub AI)
  • Separate Contexts: Sessions maintain their own conversation history, working directory, and settings
  • Quick Switching: Use :Chat prev and :Chat next to navigate between active sessions
  • Isolated Workflows: Perfect for comparing model responses or working on multiple projects simultaneously

Workflow Example:

  1. Start a session with DeepSeek: :Chat new (then select DeepSeek model)
  2. Switch to GitHub AI for a different task: :Chat new (select GitHub model)
  3. Toggle between sessions: :Chat prev / :Chat next
  4. Each session preserves its unique context and conversation flow

Examples

  1. Start a new conversation:

    :Chat new

    This creates a fresh session and opens the chat window.

  2. Resume a previous conversation:

    :Chat prev

    Cycles backward through your saved sessions.

  3. Switch to the next conversation:

    :Chat next

    Cycles forward through your saved sessions.

  4. Open or forced to the chat window:

    :Chat

    This command will not change current sessions.

  5. Delete current session:

    :Chat delete

    Cycles to next session or create a new session if current session is latest one.

  6. Change the working directory of current session:

    :Chat cd ../picker.nvim/

    If the current session is in progress, the working directory will not be changed, and a warning message will be printed.

  7. Clear messages in current session:

    :Chat clear

    If the current session is in progress, a warning message will be printed, and current session will not be cleared. This command also will forced to chat window.

  8. Work with multiple parallel sessions:

    " Start first session with DeepSeek
    :Chat new
    " Select DeepSeek as provider and choose a model
    
    " Start second session with GitHub AI
    :Chat new
    " Select GitHub as provider and choose a model
    
    " Switch between sessions
    :Chat prev  " Go to first session
    :Chat next  " Go to second session

    This enables simultaneous conversations with different AI assistants for different tasks.

All sessions are automatically saved and can be resumed later. For more advanced session management, see the Picker Integration section below.

Key Bindings

Note: The plugin is currently in active development phase. Key bindings may change and may reflect the author's personal preferences. Configuration options for customizing key bindings are planned for future releases.

The following key bindings are available in the Input window:

Mode Key Binding Description
Normal <Enter> Send message
Normal q Close chat window
Normal <Tab> Switch between input and result windows
Normal Ctrl-C Cancel current request
Normal Ctrl-N Open new session
Normal r Retry last cancelled request
Normal alt-h previous chat session
Normal alt-l next chat session
Normal <Leaer>fr run :Picker chat
Normal <Leaer>fp run :Picker chat_provider
Normal <Leader>fm run :Picker chat_model

The following key bindings are available in the Result window:

Mode Key Binding Description
Normal q Close chat window
Normal <Tab> Switch between input and result windows

🤖 Providers

Built-in Providers

  1. deepseek - DeepSeek AI
  2. github - GitHub AI
  3. moonshot - Moonshot AI
  4. openrouter - OpenRouter
  5. qwen - Alibaba Cloud Qwen
  6. siliconflow - SiliconFlow
  7. tencent - Tencent Hunyuan
  8. bigmodel - BigModel AI
  9. volcengine - Volcengine AI

Custom Providers

chat.nvim also supports custom provider, just create lua/chat/providers/<provider_name>.lua, this lua module should provides two functions request and available_models, here is an example for using free_chatgpt_api

file: ~/.config/nvim/lua/chat/provides/free_chatgpt_api.lua

local M = {}
local job = require('job')
local sessions = require('chat.sessions')
local config = require('chat.config')

function M.available_models()
  return {
    'gpt-4o-mini',
  }
end

function M.request(requestObj)
  local cmd = {
    'curl',
    '-s',
    'https://free.v36.cm/v1/chat/completions',
    '-H',
    'Content-Type: application/json',
    '-H',
    'Authorization: Bearer ' .. config.config.api_key.free_chatgpt,
    '-X',
    'POST',
    '@-',
  }

  local body = vim.json.encode({
    model = sessions.get_session_model(opt.session),
    messages = opt.messages,
    thinking = {
      type = 'enabled',
    },
    stream = true,
    stream_options = { include_usage = true },
    tools = require('chat.tools').available_tools(),
  })

  local jobid = job.start(cmd, {
    on_stdout = opt.on_stdout,
    on_stderr = opt.on_stderr,
    on_exit = opt.on_exit,
  })
  job.send(jobid, body)
  job.send(jobid, nil)
  sessions.set_session_jobid(opt.session, jobid)

  return jobid
end

return M

Tools

chat.nvim supports tool call functionality, allowing the AI assistant to interact with your filesystem, manage memories, and perform other operations during conversations. Tools are invoked using the @tool_name syntax directly in your messages.

Available Tools

read_file

Reads the content of a file and makes it available to the AI assistant.

Usage:

@read_file <filepath>

Examples:

  • @read_file ./src/main.lua - Read a Lua file in the current directory
  • @read_file /etc/hosts - Read a system file using absolute path
  • @read_file ../config.json - Read a file from a parent directory

Advanced Usage with Line Ranges:

@read_file ./src/main.lua line_start=10 line_to=20

Notes:

  • File paths can be relative to the current working directory or absolute
  • Supports line range selection with line_start and line_to parameters
  • Line numbers are 1-indexed (first line is line 1)
  • If line_start is not specified, defaults to line 1
  • If line_to is not specified, defaults to last line
  • The AI will receive the file content for context
  • This is particularly useful for code review, debugging, or analyzing configuration files

find_files

Finds files in the current working directory that match a given pattern.

Usage:

@find_files <pattern>

Examples:

  • @find_files *.lua - Find all Lua files in the current directory
  • @find_files **/*.md - Recursively find all Markdown files
  • @find_files src/**/*.js - Find JavaScript files in the src directory and its subdirectories
  • @find_files README* - Find files starting with "README"

Notes:

  • The pattern follows Vim's globpath syntax
  • Searches are limited to the current working directory
  • Returns a list of found files, with one file path per line
  • Returns a message if no files are found based on the given pattern
  • File searching is restricted by the allowed_path configuration setting

search_text

Advanced text search tool using ripgrep (rg) to search text content in directories with regex support, file type filtering, exclusion patterns, and other advanced features.

Usage:

@search_text <pattern> [options]

Basic Examples:

  • @search_text "function.*test" - Search for regex pattern in current directory
  • @search_text "TODO:" --file-types "*.lua" - Search TODO comments in Lua files
  • @search_text "error" --context-lines 2 - Search for "error" with 2 lines of context

Advanced Usage with JSON Parameters:

For more complex searches, you can provide a JSON object with multiple parameters:

@search_text {"pattern": "function.*test", "directory": "./src", "file_types": ["*.lua", "*.vim"], "ignore_case": true, "max_results": 50}

Parameters:

Parameter Type Description
pattern string Required. Text pattern to search for (supports regex)
directory string Directory path to search in (default: current working directory)
ignore_case boolean Whether to ignore case (default: false)
regex boolean Whether to use regex (default: true)
max_results integer Maximum number of results (default: 100)
context_lines integer Number of context lines to show around matches (default: 0)
whole_word boolean Whether to match whole words only (default: false)
file_types array File type filter, e.g., ["*.py", "*.md", "*.txt"]
exclude_patterns array Exclude file patterns, e.g., ["*.log", "tmp/*"]

More Examples:

  1. Case-insensitive search:

    @search_text {"pattern": "config", "ignore_case": true}
    
  2. Search with file type filtering:

    @search_text {"pattern": "function", "file_types": ["*.lua", "*.vim"]}
    
  3. Search with context and exclusions:

    @search_text {"pattern": "FIXME", "context_lines": 3, "exclude_patterns": ["*.log", "node_modules/*"]}
    
  4. Whole word matching:

    @search_text {"pattern": "test", "whole_word": true}
    

Notes:

  • Uses ripgrep (rg) for fast, powerful text searching
  • Supports full regex syntax for complex pattern matching
  • Search is restricted by the allowed_path configuration setting
  • Returns matching lines with file paths and line numbers
  • If no matches are found, returns an informative message
  • Particularly useful for code analysis, debugging, and finding references

extract_memory

Extract long-term memories from conversation text, focusing ONLY on factual information and habitual patterns. Filters out subjective feelings, temporary states, and irrelevant chatter.

Usage:

@extract_memory <parameters>

Examples:

  • @extract_memory text="Python的GIL是全局解释器锁,我习惯用Vim写代码" category="fact"
  • @extract_memory text="我每天早晨6点起床锻炼,通常下午3点喝咖啡" category="preference"

Parameters:

Parameter Type Description
text string Text to analyze for memory extraction
memories array Pre-extracted memories array (alternative to text parameter)
category string Suggested category: "fact", "preference", "skill", or "event"

Category Definitions:

  • fact: Verifiable objective facts, data, definitions, rules
  • preference: Personal habits, routine behaviors, regular practices
  • skill: Technical abilities and knowledge
  • event: Specific events and occurrences

Notes:

  • Extracts only persistent and reusable information
  • Automatically detects categories based on keywords
  • Supports both raw text analysis and pre-processed memories
  • Memory system must be enabled in chat.nvim configuration

recall_memory

Retrieve relevant information from long-term memory and add to current conversation. Automatically extracts keywords if no query is provided.

Usage:

@recall_memory <parameters>

Examples:

  • @recall_memory query="vim configuration"
  • @recall_memory query="programming tips" limit=8
  • @recall_memory (automatically extracts keywords from current conversation)

Parameters:

Parameter Type Description
query string Search query (optional, auto-extracted if not provided)
limit integer Number of results (default: 5, maximum: 10)
all_sessions boolean Search all sessions instead of just current (default: false)

Notes:

  • Returns formatted memory list that AI can reference for responses
  • Searches across categories and content
  • Shows timestamps and contextual information
  • Memory system must be enabled in chat.nvim configuration
  • Useful for maintaining context across conversations

set_prompt

Read a prompt file and set it as the current session's system prompt.

Usage:

@set_prompt <filepath>

Examples:

  • @set_prompt ./AGENTS.md
  • @set_prompt ./prompts/code_review.txt
  • @set_prompt ~/.config/chat.nvim/default_prompt.md

Parameters:

Parameter Type Description
filepath string Path to prompt file

Notes:

  • Updates the current session's system prompt with file content
  • File must be within the allowed_path configured in chat.nvim
  • Useful for switching between different agent roles or task-specific prompts
  • Supports relative and absolute paths

Third-party Tools

zettelkasten_create

Create new zettelkasten notes, provided by zettelkasten.nvim.

Usage:

@zettelkasten_create <parameters>

Parameters:

Parameter Type Description
title string The title of zettelkasten note
content string The note body of zettelkasten
tags array Optional tags for the note (max 3)

Notes:

  • Creates a new zettelkasten note with specified title and content
  • Tags should be in English and limited to 3 to avoid synonyms
  • Integration with zettelkasten.nvim plugin

zettelkasten_get

Retrieve zettelkasten notes by tags, provided by zettelkasten.nvim.

Usage:

@zettelkasten_get <tags>

Parameters:

Parameter Type Description
tags array Tags to search for (e.g., ["programming", "vim"])

Notes:

  • Returns JSON object containing matching notes
  • Each note includes file_name and title fields
  • Tags should be in English
  • Integration with zettelkasten.nvim plugin

How to Use Tools

  1. Direct invocation: Include the tool call directly in your message:

    Can you review this code? @read_file ./my_script.lua
    
  2. Multiple tools: Combine multiple tools in a single message:

    Compare these two configs: @read_file ./config1.json @read_file ./config2.json
    
  3. Natural integration: The tool calls can be embedded naturally within your questions:

    What's wrong with this function? @read_file ./utils.lua
    
  4. Memory management: Use memory tools for context-aware conversations:

    Based on what we discussed earlier about Vim: @recall_memory query="vim"
    

The AI assistant will process the tool calls, execute the specified operations, and incorporate their results into its response. This enables more context-aware assistance without needing to manually copy-paste file contents or repeat previous information.

Custom Tools

chat.nvim also supports custom tools. Users can create lua/chat/tools/<tool_name>.lua file in their Neovim runtime path.

This module should provide at least two functions: scheme() and <tool_name> function. The scheme() function returns a table describing the tool's schema (name, description, parameters). The <tool_name> function is the actual implementation that will be called when the tool is invoked.

The tools.lua module automatically discovers all tools in the lua/chat/tools/ directory and provides an available_tools() function to list them, and a call(func, arguments) function to invoke a specific tool.

Here is an example for a get_weather tool:

local M = {}

---@param action { city: string, unit?: string }
function M.get_weather(action)
  if not action.city or action.city == '' then
    return {
      error = 'City name is required for weather information.',
    }
  end

  local unit = action.unit or 'celsius'
  local valid_units = { 'celsius', 'fahrenheit' }
  if not vim.tbl_contains(valid_units, unit) then
    return {
      error = 'Unit must be either "celsius" or "fahrenheit".',
    }
  end

  -- Simulate fetching weather data (in a real implementation, you would call an API here)
  local temperature = math.random(15, 35)  -- Random temperature between 15°C and 35°C
  local conditions = { 'Sunny', 'Cloudy', 'Rainy', 'Partly Cloudy', 'Windy' }
  local condition = conditions[math.random(1, #conditions)]

  -- Convert temperature if needed
  if unit == 'fahrenheit' then
    temperature = math.floor((temperature * 9/5) + 32)
  end

  return {
    content = string.format(
      'Weather in %s:\n- Temperature: %d°%s\n- Condition: %s\n- Humidity: %d%%\n- Wind Speed: %d km/h',
      action.city,
      temperature,
      unit == 'celsius' and 'C' or 'F',
      condition,
      math.random(40, 90),
      math.random(5, 25)
    ),
  }
end

function M.scheme()
  return {
    type = 'function',
    ['function'] = {
      name = 'get_weather',
      description = 'Get weather information for a specific city. Use @get_weather {city: "City Name"} to get weather details.',
      parameters = {
        type = 'object',
        properties = {
          city = {
            type = 'string',
            description = 'City name for weather information',
          },
          unit = {
            type = 'string',
            description = 'Temperature unit: "celsius" or "fahrenheit"',
            enum = { 'celsius', 'fahrenheit' },
          },
        },
        required = { 'city' },
      },
    },
  }
end

return M

🔍 Picker Integration

chat.nvim provides built-in picker sources for seamless integration with picker.nvim. These sources allow you to quickly access and manage your chat sessions, providers, and models.

Note: The chat picker source displays all your active sessions, allowing quick switching between parallel conversations with different models.

Available Sources:

  1. chat - Search through your chat history sessions

    • Uses the first message of each session as the search string
    • Quickly resume previous conversations
    • Supports filtering and session management picker-chat
  2. chat_provider - Switch between different AI providers

    • Dynamically change between supported providers (DeepSeek, OpenAI, etc.)
    • Real-time switching without restarting Neovim picker-chat
  3. chat_model - Select available models for the current provider

    • Lists all compatible models for your selected provider
    • Intelligent filtering based on provider capabilities picker-chat

📣 Self-Promotion

Like this plugin? Star the repository on GitHub.

Love this plugin? Follow me on GitHub.

💬 Feedback

If you encounter any bugs or have suggestions, please file an issue in the issue tracker.

📄 License

This project is licensed under the GPL-3.0 License.

About

A lightweight Lua chat plugin for Neovim with AI integration.

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

Languages