跳到主要内容
非官方简体中文翻译,内容版权归 Mastra 所有,遵循 Apache-2.0 许可。

LSP inspection

Language Server Protocol (LSP) 检查为 agents 提供有关项目代码的语义信息。语言服务器可以识别符号的类型、声明、实现和诊断,因为它理解语言和项目结构。

LSP 增加了什么
LSP 增加了什么的直接链接

文件工具和搜索工具回答关于代码库的不同问题:

工具最适合
read_file读取已知文件的精确内容和周围上下文
grep在文件中查找文本或正则表达式匹配
搜索按关键词或语义相似度检索已索引文件
LSP 检查获取类型感知信息并跨项目跟踪符号

LSP 检查补充这些工具,而不是替代它们。Agent 可以使用 grep 找到符号,并通过 LSP 检查来定位其声明。然后可以使用 read_file 读取完整实现,再进行更改。

设置 LSP
设置 LSP的直接链接

LSP 会启动一个长时间运行的语言服务器进程,并与其交换 JSON-RPC 消息。在启用 LSP 之前,请确保你的配置包含:

  • 一个静态 sandbox,其进程管理器的进程句柄提供可读输出和可写输入流。不支持 sandbox 解析器。
  • 在 Mastra 应用中安装 vscode-jsonrpc 和 vscode-languageserver-protocol 包。
  • 在 sandbox 进程运行的位置安装语言服务器二进制文件及其 runtime。
  • 一个绝对项目根目录,以及可通过匹配路径同时供 Mastra 应用和 sandbox 进程访问的项目文件。

Mastra 为 TypeScript 和 JavaScript、Python、Go 和 Rust 内置了服务器定义。匹配的语言服务器二进制文件仍需安装。对于其他文件类型,你可以注册另一个服务器。

安装共享协议包:

npm install vscode-jsonrpc vscode-languageserver-protocol

然后为你的项目安装语言服务器。例如,安装 TypeScript 及其语言服务器:

npm install typescript typescript-language-server

创建一个静态 LocalSandbox,并将文件系统、sandbox 和 LSP 根目录指向同一目录:

src/mastra/workspaces.ts
import { resolve } from 'node:path'
import { LocalFilesystem, LocalSandbox, Workspace } from '@mastra/core/workspace'

const projectPath = resolve('./workspace')

export const workspace = new Workspace({
filesystem: new LocalFilesystem({
basePath: projectPath,
}),
sandbox: new LocalSandbox({
workingDirectory: projectPath,
}),
lsp: {
root: projectPath,
},
})

文件系统为 agent 提供处理项目文件的工具。当 LSP 查询首次需要时,sandbox 会在同一目录中启动语言服务器。如果任何必需的协议包、进程管理器或服务器二进制文件不可用,Mastra 会禁用 LSP 或返回没有可用的语言服务器。

使用 agent 工具检查代码
使用 agent 工具检查代码的直接链接

启用 LSP 后,agent 会收到 mastra_workspace_lsp_inspect。其输入标识一个文件并将光标放在一个符号上:

{
"path": "/absolute/path/to/workspace/src/orders.ts",
"line": 10,
"match": "const order = await <<<findOrder(orderId)"
}

line 从 1 开始索引。将该行的内容复制到 match,然后在要检查的符号前面插入恰好一个 <<< 标记。该标记不属于源文件。

该工具返回语言服务器能够提供的字段:

字段输出
hover类型信息或文档,以及其标记类型
diagnostics被检查行上诊断的严重性、消息和来源
definition声明位置,在文件可读时附带一行预览
implementation实现位置
error检查无法运行时的设置、服务器或查询错误

不可用的结果字段会被省略。定义和实现位置标识了应使用 read_file 继续获取完整上下文的位置。

配置 LSP
配置 LSP的直接链接

设置 lsp: true 以使用默认值。当需要控制根目录、服务器发现、超时或保留的客户端时,将其替换为对象:

lsp: {
root: projectPath,
diagnosticTimeout: 4_000,
initTimeout: 8_000,
maxOpenClients: 4,
disableServers: ['eslint'],
binaryOverrides: {
typescript: '/opt/mastra-tools/typescript-language-server --stdio',
},
searchPaths: ['/opt/mastra-tools'],
},

binaryOverrides 将内置服务器 ID 映射到其完整启动命令。searchPaths 添加包根目录,其 node_modules 可能包含所需模块或二进制文件。作为最后手段的回退,你可以设置 packageRunner,例如 pnpm dlx。Package-runner 回退默认禁用,因为它可能会安装软件或在某些项目布局中挂起。

diagnosticTimeout 控制直接调用 getDiagnostics() 和 getDiagnosticsMulti() API 等待诊断的时间。Agent 检查工具目前最多等待五秒。

Mastra 通常会通过向上查找该服务器的项目标记来为每个文件找到项目根目录。找不到标记时,它会回退到 lsp.root。关于所有选项和默认值,请参阅 LSP 配置参考。

限制保留的客户端
限制保留的客户端的直接链接

maxOpenClients 限制为单个配置保留的语言服务器客户端数量。它必须是正整数。达到上限时,Mastra 会关闭最近最少使用且没有活动查询租约的客户端。

如果每个保留的客户端都有活动租约,下一次获取会最多等待五秒以等待某个租约释放。如果仍没有可用的,prepareQuery() 和 getDiagnostics() 返回 null。getDiagnosticsMulti() 会省略无法获取的服务器。省略 maxOpenClients 会使保留客户端数量不受限制。Mastra Code 使用默认上限 4。

工具名称重映射
工具名称重映射的直接链接

通过 tools 配置 agent 检查工具。例如,添加以下条目以暴露更短的名称:

import { WORKSPACE_TOOLS } from '@mastra/core/workspace'

const tools = {
[WORKSPACE_TOOLS.LSP.LSP_INSPECT]: {
name: 'lsp_inspect',
},
}

在配置中将 tools 与 lsp 并列添加。name 会更改暴露的工具名称,但配置键仍为 WORKSPACE_TOOLS.LSP.LSP_INSPECT。在同一 entry 上设置 enabled: false 可移除该工具。

关于生成的 agent 工具共享的审批设置、动态策略、输出限制和 hooks,请参阅工具配置参考。

自定义语言服务器
自定义语言服务器的直接链接

当某种语言不是内置的,或需要替换内置定义时,在 lsp.servers 下添加服务器:

lsp: {
root: projectPath,
servers: {
phpactor: {
id: 'phpactor',
name: 'Phpactor Language Server',
languageIds: ['php'],
extensions: ['.php'],
markers: ['composer.json'],
command: 'phpactor language-server',
initializationOptions: {
indexer: { enabled: true },
},
},
},
},

每个定义支持以下字段:

字段必需描述
id是唯一的服务器 ID。使用内置 ID 可替换该定义。
name是用于日志和错误的可读名称。
languageIds是服务器处理的 LSP 语言标识符。
extensions是服务器处理的文件扩展名,包括点号。
markers是用于查找项目根目录的文件或目录。
command是启动服务器的完整命令。
initializationOptions否在 LSP 初始化握手期间发送的设置。

自定义定义会与内置定义合并。具有相同 id 的自定义定义会替换内置定义。当服务器列出多个语言 ID 时,Mastra 会将每个配置的扩展名映射到第一个 ID。

直接查询 LSP
直接查询 LSP的直接链接

应用代码可以直接查询配置的 LSP 管理器。getDiagnostics() 和 getDiagnosticsMulti() 会在内部管理其客户端租约以及文档打开和关闭通知。

prepareQuery() 暴露客户端以进行 hover、definition、implementation 和其他直接查询。向它传入绝对文件路径。它会打开文件并返回租约。在释放该租约之前关闭文件,并将两个调用都放在 finally 块中:

async function inspectHover(filePath: string, line: number, character: number) {
const query = await workspace.lsp?.prepareQuery(filePath)
if (!query) return null

try {
return await query.client.queryHover(query.uri, {
line,
character,
})
} finally {
query.client.notifyClose(filePath)
query.release()
}
}

直接客户端位置从 0 开始索引。泄漏的租约可能会在设置了 maxOpenClients 时阻止空闲客户端被驱逐。在拆卸期间,Mastra 会最多等待五秒以等待活动租约,然后强制关闭语言服务器。受管理的 LSP 客户端会在 sandbox 销毁之前关闭。

限制
限制的直接链接

  • LSP 仅适用于具有匹配的内置或自定义服务器的文件类型。
  • 仅文件系统无法运行语言服务器。LSP 需要一个带双向进程管理器的静态 sandbox。
  • LocalFilesystem 的包含限制和 allowedPaths 不会约束 LSP 检查。将 lsp.root 限制为受信任的项目,并且当用户可能提交不受信任的宿主路径时,不要暴露 LSP 工具。
  • 外部包检查可能解析到 .d.ts 等声明文件,而不是 runtime 源码。
  • 语言服务器可能会省略其不支持的 hover、diagnostic、definition 或 implementation 结果。

远程 sandboxes
远程 sandboxes的直接链接

远程 LSP 并非后端透明。语言服务器命令通过远程 sandbox 进程管理器运行,但二进制发现、文件读取和某些源码预览仍使用 Mastra 宿主。

仅在满足以下所有条件时使用远程 LSP:

  • 远程进程管理器提供可读输出和可写输入流。
  • 项目在 Mastra 宿主和远程 sandbox 中使用匹配的绝对路径。
  • 解析后的服务器命令已安装在远程镜像中。对于内置服务器,通过 binaryOverrides 配置;对于自定义服务器,通过 lsp.servers.command 配置。
  • 宿主可以读取检查和定义预览所需的文件。

本地文件系统和远程 sandbox 不会自动同步。仅安装在宿主上的二进制文件无法在远程 sandbox 中运行,而仅存在于远程的文件无法提供所有宿主侧结果。对于仅远程项目,请使用 grep、已索引的搜索和 sandbox 命令,直到 LSP 文件访问实现后端透明。