Files
AstrBot/openspec/lsp.md
LIghtJUNction 14a1e37261 docs: 更新 openspec 规范文档
- 添加实现状态表格
- 更新配置规范
- 添加新的协议规范
2026-03-27 19:10:49 +08:00

10 KiB
Raw Blame History

LSP (Language Server Protocol) 协议规范

概述

LSPLanguage Server Protocol是由 Microsoft 制定的开放协议,用于在编辑器/IDE 与语言智能服务之间提供语言特性支持。

核心问题:传统上,为编辑器提供编程语言支持(如自动完成、跳转到定义)需要针对每个编辑器/IDE 单独实现。例如Eclipse CDT 插件用 Java 编写VS Code 扩展用 TypeScript 编写C# 支持用 C# 编写。

解决方案:语言服务器在其自己的进程中运行,编辑器通过标准协议与之通信。只需实现一次语言服务器,即可集成到任何支持 LSP 的工具中。

实现状态

组件 状态 说明
LSP Client 不计划 AstrBot 不作为 LSP 客户端使用(用于 IDE 集成)
LSP Server 不计划 作为 AI 编程助手,暂无语言服务器需求
参考文档 完成 本文档为 LSP 协议参考,不做实现

相关协议: A2AAgent 间通信), agent-message(消息处理框架)

参考Language Server Protocol by Microsoft

设计哲学

抽象层级

LSP 成功的原因在于其编辑器级别的抽象,而非编程语言领域模型级别:

层级 LSP 抽象 传统方法
编辑器级别 文本文档 URI、光标位置
语言模型级别 抽象语法树、编译器符号

简化协议:标准化文本文档 URI 或光标位置,比标准化抽象语法树和编译器符号简单得多。

进程隔离

┌─────────────────────────────────────┐
│           编辑器/IDE                │
│  - 文档状态管理                    │
│  - 用户交互                        │
│  - UI 渲染                         │
└─────────────────────────────────────┘
                      │ JSON-RPC 2.0
                      ▼
┌─────────────────────────────────────┐
│         语言服务器 (独立进程)        │
│  - 词法分析                        │
│  - 语法分析                        │
│  - 类型检查                        │
│  - 代码生成                         │
└─────────────────────────────────────┘

优势

  • 避免与单个进程模型相关的性能问题
  • 语言服务器可用任何语言实现Python、Go、JavaScript 等)
  • 服务器崩溃不影响编辑器

架构

通信流程

┌─────────────────────────────────────┐
│           编辑器/IDE (LSP 客户端)    │
└─────────────────────────────────────┘
                      │ JSON-RPC 2.0
                      ▼
┌─────────────────────────────────────┐
│         LSP 服务器 (独立进程)        │
│  - 代码补全                         │
│  - 诊断(错误、警告)               │
│  - 悬停信息                         │
│  - 跳转到定义                       │
│  - 重构支持                         │
└─────────────────────────────────────┘

传输方式

传输方式 说明
stdio 通过 stdin/stdout 通信(常用)
Socket TCP 套接字
Named Pipes 命名管道
Node IPC Node.js 进程间通信

会话流程

1. 打开文档

编辑器 → 服务器textDocument/didOpen
内容:{
  "textDocument": {
    "uri": "file:///path/to/file.py",
    "languageId": "python",
    "version": 1,
    "text": "print('hello')"
  }
}

服务器将文档内容加载到内存,不再依赖文件系统。

2. 编辑文档

编辑器 → 服务器textDocument/didChange
内容:{ "textDocument": {...}, "contentChanges": [...] }

服务器更新内存中的文档状态,分析语义信息。

3. 发布诊断

服务器 → 编辑器textDocument/publishDiagnostics
内容:{ "uri": "...", "diagnostics": [...] }

服务器通知编辑器检测到的错误和警告。

4. 跳转到定义

编辑器 → 服务器textDocument/definition
内容:{
  "textDocument": { "uri": "file:///path/to/file.py" },
  "position": { "line": 3, "character": 12 }
}

服务器 → 编辑器:响应
内容:{
  "uri": "file:///path/to/definition.py",
  "range": { "start": {...}, "end": {...} }
}

5. 关闭文档

编辑器 → 服务器textDocument/didClose
内容:{ "textDocument": { "uri": "..." } }

服务器释放文档内存,当前内容与文件系统同步。

消息格式

所有消息均为 JSON-RPC 2.0

请求

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "textDocument/definition",
  "params": {
    "textDocument": {
      "uri": "file:///path/to/file.py"
    },
    "position": {
      "line": 3,
      "character": 12
    }
  }
}

响应

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "uri": "file:///path/to/definition.py",
    "range": {
      "start": { "line": 0, "character": 4 },
      "end": { "line": 0, "character": 11 }
    }
  }
}

通知

{
  "jsonrpc": "2.0",
  "method": "textDocument/didOpen",
  "params": {
    "textDocument": {
      "uri": "file:///path/to/file",
      "languageId": "python",
      "version": 1,
      "text": "print('hello')"
    }
  }
}

错误

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32600,
    "message": "Invalid Request"
  }
}

核心方法

生命周期

方法 方向 描述
initialize C→S 初始化连接,交换能力
initialized C→S 客户端通知服务器初始化完成
shutdown C→S 请求服务器关闭
exit C→S 退出会话

文本文档同步

方法 方向 描述
textDocument/didOpen C→S 文档被打开
textDocument/didChange C→S 文档内容变更
textDocument/didClose C→S 文档被关闭
textDocument/didSave C→S 文档被保存

代码补全

方法 方向 描述
textDocument/completion C→S 请求代码补全
completionItem/resolve C→S 解析补全项详情

导航

方法 方向 描述
textDocument/hover C→S 获取悬停信息
textDocument/definition C→S 跳转到定义
textDocument/typeDefinition C→S 跳转到类型定义
textDocument/implementation C→S 跳转到实现
textDocument/references C→S 查找引用
textDocument/documentSymbol C→S 文档符号
textDocument/workspaceSymbol C→S 工作区符号搜索

代码诊断

方法 方向 描述
textDocument/publishDiagnostics S→C 服务器发布诊断信息

代码操作

方法 方向 描述
textDocument/codeAction C→S 代码动作/修复
textDocument/rename C→S 重命名符号
textDocument/formatting C→S 文档格式化
textDocument/rangeFormatting C→S 范围格式化

能力 (Capabilities)

服务器能力声明

{
  "capabilities": {
    "textDocumentSync": 2,
    "completionProvider": {
      "resolveProvider": true,
      "triggerCharacters": [".", "("]
    },
    "hoverProvider": true,
    "definitionProvider": true,
    "typeDefinitionProvider": true,
    "implementationProvider": true,
    "referencesProvider": true,
    "documentSymbolProvider": true,
    "workspaceSymbolProvider": true,
    "codeActionProvider": true,
    "renameProvider": true,
    "documentFormattingProvider": true,
    "diagnosticProvider": {
      "interFileDependencies": false,
      "workspaceDiagnostics": false
    }
  }
}

客户端能力声明

{
  "capabilities": {
    "workspace": {
      "applyEdit": true,
      "workspaceFolders": true,
      "fileOperations": {
        "willRename": true
      }
    },
    "textDocument": {
      "synchronization": {
        "willSave": true,
        "willSaveWaitUntil": true,
        "didSave": true
      },
      "completion": {
        "completionItem": {
          "snippetSupport": true,
          "documentationFormat": ["markdown", "plaintext"]
        }
      },
      "hover": {
        "contentFormat": ["markdown", "plaintext"]
      }
    }
  }
}

能力协商

服务器声明支持的功能,客户端声明支持的功能。双方只使用都支持的功能。

错误码

码值 名称 描述
-32700 Parse Error 无效的 JSON
-32600 Invalid Request 格式错误的请求
-32601 Method Not Found 未知方法
-32602 Invalid Params 无效参数
-32603 Internal Error 服务器内部错误
-32099 Server Not Initialized 服务器未初始化
-32000 Unknown Error 未知错误

数据类型

TextDocumentItem

{
  "uri": "file:///path/to/file",
  "languageId": "python",
  "version": 1,
  "text": "print('hello')"
}

Position

{
  "line": 3,
  "character": 12
}

Range

{
  "start": { "line": 0, "character": 4 },
  "end": { "line": 0, "character": 11 }
}

Location

{
  "uri": "file:///path/to/file",
  "range": { "start": {...}, "end": {...} }
}

Diagnostic

{
  "range": { "start": {...}, "end": {...} },
  "severity": 1,
  "code": "E001",
  "source": "pylint",
  "message": "Undefined variable 'x'"
}

实现注意事项

  • LSP 服务器在其自己的进程中运行,避免性能问题
  • 使用 Content-Length 头解析 JSON-RPC 消息
  • 支持增量文档同步textDocumentSync
  • 诊断信息通过 textDocument/publishDiagnostics 推送
  • 服务器应保持运行,避免每次编辑都重启进程
  • 客户端和服务器通过能力声明协商支持的功能
  • 文档内容由客户端管理,服务器无需直接访问文件系统