类型服务器协议(TSP)是一个JSON-RPC协议,用于为Python分析数据询问类型服务器。 一个类型服务器维护一个工作空间的类型分析状态,并对协议版本,快照,Python搜索路径,导入解析度,以及类型查询(计算,声明,以及预期类型)进行解答。
协议使用语言服务器协议(LSP)的数据形状和实用的常规,如位置和范围,它代表URI,就像LSP一样的字符串。 TSP方法使用类型Server/前缀。
本文件夹中的协议文物是权威定义:
- 类型ServerProtocol.ts定义了类型脚本接口和请求类型。
- Tsp.json是机器可读协议模型。
- tsp.schema.json是协议模型的JSON计划。
TSP使用语义版本字符串进行客户端/服务器兼容性检查。 当协议处于0.x行时,小版本的修改可能正在中断。 补丁版本的修改在同一小行内保持向后兼容。
一个客户端启动一个类型服务器,并在JSON-RPC主连接上使用服务器支持的传输,如stdio或Node IPC与它通信。 在使用stdio时,stdout必须保留给JSON-RPC协议消息。
一个类型服务器预计将获得足够的工作空间和文件状态,以响应它支持的TSP请求。 客户端通常为此状态使用普通的LSP初始化和文档同步,然后在同一JSON-RPC连接上发送类型Server/*请求。
TSP还支持可选的额外只读连接。 原始连接仍然是主要连接并拥有初始化,工作空间状态,文档同步,状态变化通知,以及连接控制。 只有在客户端和服务器在初始化过程中谈判支持后,才会打开额外的连接。
按此顺序排列的典型会话:
- 客户端启动或连接到类型服务器。
- 客户端和服务器初始化任何共享的工作空间状态,通常通过LSP初始化和初始化消息。
- 客户端调用类型Server/getPresided ProtocolVersion,并验证返回的Semver字符串与其预期的协议版本兼容。
- 客户端呼叫类型Server/getSnapshot来获取第一个快照标识符。
- 客户端发送类型- query、 导入- 分辨率或搜索- 路径请求,包括当请求形状需要时的当前快照。
- 服务器发送类型Server/snapshotChanged 当以前的类型结果不再有效时。
多连接模式是一个可选的性能功能。 它让一个客户端为同一类型的服务器打开额外的本地频道,用于只读的TSP请求,而主连接继续拥有可变的工作空间状态。
客户端只有在能够从同时进行的只读工作中受益时,如量大类型的查询或背景工作者,才应使用多连接模式,这些查询不应阻碍主要的JSON-RPC连接。 一个服务器仍然必须在单连接模式下正确工作。 协议正确性不得需要多连接支持。
多连接支持是通过正常的LSP初始化请求和响应来谈判的。 一个可以打开额外TSP频道的客户端在能力。 experiment.typeServer MultiConnection下广告支持的运输类型:
{
"能力":{
"实验":{
"类型Server多连接":{
"支持的运输": ["ipc"]
}
}
}
}
可以服务额外 TSP 通道的服务器在初始化结果中返回相同的容量形状:
{
"能力":{
"实验":{
"类型Server多连接":{
"支持的运输": ["ipc"]
}
}
}
}
多连接模式只有在双方广告型号Server MultiConnection和两个支持的Transport列表至少有一个通用的运输时才启用。 如果任何一方省略了能力,或者没有通用的传输,会话仍然是单连接,客户端不得发送类型Server/连接。
目前支持的额外连接的内置运输类型是ipc. 这种谈判与主连接是分开的,主连接可以使用stdio或Node IPC.
在初始化和运输谈判之后,客户端通过在主连接上发送类型Server/连接打开一个额外的通道:
{
"类型":"开"
"仁":"ip"
"args": ["<ipc-endpoint>] (中文(简体) ).
}
对于ipc,args阵列识别服务器应该连接的终点或终点。 服务器应该验证请求,迅速连接到提供的端点,并成功返回结果:接受请求时为真。 如果服务器无法打开频道,它应该返回成功:错误,并且包含一个对日志有用的短消息。
当平台IPC机制支持时,ipc端点预计将提供全复式JSON-RPC流。 在这种情况下,参数包含一个终点字符串:
{
"类型":"开"
"仁":"ip"
"args": ["<full-duplex-ipc-endpoint>] (中文(简体) ).
}
如果平台IPC机制只暴露单向端点,则args包含两个端点字符串。 端点名称来自类型服务器的视角:第一个端点是服务器输入流,第二个端点是服务器输出流。
{
"类型":"开"
"仁":"ip"
"args":["<输入-ipc-endpoint>","<输出-ipc-endpoint>]]].
}
客户端通过发送类型Server/连接到同一运输类型和端点身份的主要连接上来关闭一个额外的通道:
{
"类型":"接近"
"仁":"ip"
"args": ["<ipc-endpoint>] (中文(简体) ).
}
服务器应当停止服务匹配的额外通道,并迅速关闭传输。 如果服务器未在客户端的超时预算内完成关闭,客户端也可以拆除其本地运输。
近端请求应当使用打开通道的相同方格形状:一个完整复式IPC流的端点,或者一个拆分的IPC流的相同输入/输出端点对。
主要连接拥有所有改变状态的流量。 下列情况必须保持主连接:
- LSP初始化和生命周期信息。
- 工作空间、配置、文件监视器和文件同步通知。
- 服务器对客户快照通知。
- Server/连接控制请求。
额外的连接是 TSP 仅读。 它们可能被用于不突变服务器状态的请求,其结果对客户端提供的快照有效。
在额外连接上允许的TSP消息与谈判的TSP版本绑定。 如果一个服务器报告支持一个TSP版本并为该会话发布多连接支持的广告,它必须支持为该版本定义的每一个额外连接的TSP消息。
下表列出首先允许每个消息在额外连接上的 TSP 版本:
服务器应拒绝LSP流量,状态变化通知,类型Server/连接,以及任何在额外连接收到时不允许谈判的TSP版本的TSP消息。
一个快照是一个非负整数,它能识别类型服务器分析状态的点-时间视图。 类型控件、声明、符号和其他返回对象仅对返回时的快照有效,除非另有明确请求。
当先前返回的类型分析结果无效时,类型服务器必须推进快照。 典型的无效事件包括打开文件更改,关闭文件,配置更改,被监视文件更改,依赖性更改,或任何更改分析结果的缓存重置。
快照规则:
- 类型Server/getSnapshot 返回当前快照标识符。
- 不得在会议期间减少快照识别器。
- 类型Server/snapshotChanged报告上一个和新的快照标识符。
- 包含 Stale 快照的请求会因 JSON- RPC 错误而失败,让客户端用新快照重试。 LSP的服务器无效错误代码(-32802)是这个案例的首选错误。
TSP遵循LSP的立场公约:
- 线路是零基的
- 字符偏移是零基的UTF-16代码单元。
- 使用起始位置和终点位置确定源段。
如果一个类型服务器在另一个编码中存储源位置,它必须转换协议边界的位置。 不正确的转换可能导致客户端请求错误的语法节点的信息。
类型query请求(类型Server/getComputedType,类型Server/getDecaledType,类型Server/getExpectedType)以节点或声明的参数识别源构造。 节点是URI+源范围。 声明描述一个符号的定义地点和方式,或者是一个由源 AST 节点支持的常规声明,或者是一个由类型检查器创建且没有源节点的合成声明。
无效的 Handle 是 - 1,并代表一个无效或无法使用的控件。 客户端和服务器应当将其作为一个哨卡值,而不是一个有效的对象标识符。
类型结果为 JSON 可序列标记的对象。 每个类型都包含一个歧视者,告诉客户如何解释其他对象。 协议支持内置类型,声明类型,函数,类,联盟,模块,类型变量,超载集,合成类型,以及类型引用。
每个类型对象都带有一个数字类型的区分符,一个数字代号,和一个位域的旗帜:
类型对象为快照绑定,类型ID为响应-局部:
- 返回类型对象只对生成它的请求所使用的快照有效。
- 类型ID用于将类型参考对象与同一序列化响应图中较早的类型对象连接起来。
- 身份证类型不是一张快照的稳定的全球身份,不应在不同的答复中进行比较。
- 应使用类型参考,以避免在一个答复中重复大型或递归型图表。
目前的协议是故意小的。 确切的参数和结果形状在协议文物中定义;下表列出每个带有方向和有效载荷形状的TSP消息。
一个类型服务器应当执行它与客户端集成并返回未定义的信息,只有在协议的结果类型允许的情况下。
三种类型query请求因同一节点或声明而不同:
- 类型Server/getComputedType返回从代码流推断出来的类型。 在缩小 到 int 后,b = a + 1 中的 b 类型计算为 int。
- 类型Server/getDeclaredType 返回来源中明确写入的类型。 对于 def foo(a:int QQ str),所申报的型号是 int QQ str.
- 类型Server/getExpectedType返回周围上下文所期望的类型。 对于调用foo(4),预期的论证类型是int QQ str.
使用标准的JSON-RPC错误响应。
错误应当包含足够的消息细节,使客户端日志能够识别失败的请求,但错误不应当暴露本地机密或只显示执行状态。
兼容类型服务器应验证这些行为:
- 类型Server/get 支持协议Version 返回客户端支持的 semver 字符串。
- 所有请求和通知的有效载荷都按照规程对文物进行序列化和去序列化。
- 类型Server/getSnapshot返回非阴性快照,快照不会往后走。
- 文档、配置和监视文件更改在可以更改返回分析数据时使快照失效。
- 带有 Stale 快照的请求以可重试的取消错误失败。
- 位置和范围转换采用基于零的UTF-16常规。
- 导入解析请求返回文件URI或根据协议结果类型没有结果。
- 对客户端提供的快照进行类型查询(计算、申报和预期)返回成型良好或未定义的类型对象。
- 多连接支持只有在服务器能够服务于谈判后的额外运输时才发布广告。
- 额外连接接受允许的每个 TSP 请求
本文由 AI图鉴自动抓取并翻译,版权归原作者所有;如需查看原文请点下方链接。
The Type Server Protocol (TSP) is a JSON-RPC protocol for asking a type server for Python analysis data. A type server maintains the type-analysis state for a workspace and answers requests for the protocol version, snapshots, Python search paths, import resolution, and type queries (computed, declared, and expected types).
The protocol uses Language Server Protocol (LSP) data shapes and conventions where they are useful, such as Position and Range, and it represents URIs as strings the same way LSP does. TSP methods use the typeServer/ prefix.
The protocol artifacts in this folder are the authoritative definitions:
- typeServerProtocol.ts defines the TypeScript interfaces and request types.
- tsp.json is the machine-readable protocol model.
- tsp.schema.json is the JSON schema for the protocol model.
TSP uses semantic version strings for client/server compatibility checks. While the protocol is in the 0.x line, minor version changes may be breaking. Patch version changes remain backward compatible within the same minor line.
A client starts a type server and communicates with it over the main JSON-RPC connection using a transport the server supports, such as stdio or Node IPC. When using stdio, stdout must be reserved for JSON-RPC protocol messages.
A type server is expected to receive enough workspace and document state to answer the TSP requests it supports. Clients commonly use normal LSP initialization and document synchronization for this state, then send typeServer/* requests on the same JSON-RPC connection.
TSP also supports optional extra read-only connections. The original connection remains the main connection and owns initialization, workspace state, document synchronization, state-changing notifications, and connection control. Extra connections are opened only after client and server negotiate support during initialization.
A typical session follows this order:
- The client starts or connects to the type server.
- The client and server initialize any shared workspace state, commonly through the LSP initialize and initialized messages.
- The client calls typeServer/getSupportedProtocolVersion and verifies that the returned semver string is compatible with the protocol version it expects.
- The client calls typeServer/getSnapshot to obtain the first snapshot identifier.
- The client sends type-query, import-resolution, or search-path requests that include the current snapshot when required by the request shape.
- The server sends typeServer/snapshotChanged when prior type results are no longer valid.
Multi-connection mode is an optional performance feature. It lets a client open additional local channels to the same type server for read-only TSP requests, while the main connection continues to own the mutable workspace state.
Clients should use multi-connection mode only when they can benefit from concurrent read-only work, such as high-volume type queries or background workers that should not block the main JSON-RPC connection. A server must still work correctly in single-connection mode. Multi-connection support must not be required for protocol correctness.
Multi-connection support is negotiated through the normal LSP initialize request and response. A client that can open extra TSP channels advertises the supported transport kinds under capabilities.experimental.typeServerMultiConnection:
{
"capabilities": {
"experimental": {
"typeServerMultiConnection": {
"supportedTransports": ["ipc"]
}
}
}
}
A server that can serve extra TSP channels returns the same capability shape in the initialize result:
{
"capabilities": {
"experimental": {
"typeServerMultiConnection": {
"supportedTransports": ["ipc"]
}
}
}
}
Multi-connection mode is enabled only when both sides advertise typeServerMultiConnection and the two supportedTransports lists have at least one transport in common. If either side omits the capability, or if there is no common transport, the session remains single-connection and the client must not send typeServer/connection.
The currently supported built-in transport kind for extra connections is ipc. This negotiation is separate from the main connection, which can use stdio or Node IPC.
After initialization and transport negotiation, the client opens an extra channel by sending typeServer/connection on the main connection:
{
"type": "open",
"kind": "ipc",
"args": ["<ipc-endpoint>"]
}
For ipc, the args array identifies the endpoint or endpoints that the server should connect to. The server should validate the request, connect to the supplied endpoint promptly, and return a result with success: true when it accepts the request. If the server cannot open the channel, it should return success: false and include a short message when useful for logs.
An ipc endpoint is expected to provide a full-duplex JSON-RPC stream when the platform IPC mechanism supports it. In that case, args contains one endpoint string:
{
"type": "open",
"kind": "ipc",
"args": ["<full-duplex-ipc-endpoint>"]
}
If the platform IPC mechanism exposes only one-way endpoints, args contains two endpoint strings. The endpoint names are from the type server's perspective: the first endpoint is the server input stream, and the second endpoint is the server output stream.
{
"type": "open",
"kind": "ipc",
"args": ["<input-ipc-endpoint>", "<output-ipc-endpoint>"]
}
The client closes an extra channel by sending typeServer/connection on the main connection with the same transport kind and endpoint identity:
{
"type": "close",
"kind": "ipc",
"args": ["<ipc-endpoint>"]
}
The server should stop serving the matching extra channel and close the transport promptly. A client may also tear down its local transport if the server does not complete the close within the client's timeout budget.
The close request should use the same args shape that opened the channel: one endpoint for a full-duplex IPC stream, or the same input/output endpoint pair for a split IPC stream.
The main connection owns all state-changing traffic. The following must remain main-connection-only:
- LSP initialization and lifecycle messages.
- Workspace, configuration, file-watcher, and document synchronization notifications.
- Server-to-client snapshot notifications.
- The typeServer/connection control request.
Extra connections are TSP-only and read-only. They may be used for requests that do not mutate server state and whose results are valid for the snapshot supplied by the client.
The allowed TSP messages on an extra connection are bound to the negotiated TSP version. If a server reports support for a TSP version and advertises multi-connection support for that session, it must support every extra-connection TSP message defined for that version.
The table below lists the TSP version that first allows each message on an extra connection:
Servers should reject LSP traffic, state-changing notifications, typeServer/connection, and any TSP message not allowed for the negotiated TSP version when received on an extra connection.
A snapshot is a non-negative integer that identifies a point-in-time view of the type server's analysis state. Type handles, declarations, symbols, and other returned objects are valid only for the snapshot in which they were returned unless a request explicitly says otherwise.
The type server must advance the snapshot whenever a previously returned type-analysis result may be invalid. Typical invalidating events include opened-file changes, closed files, configuration changes, watched-file changes, dependency changes, or any cache reset that changes analysis results.
Snapshot rules:
- typeServer/getSnapshot returns the current snapshot identifier.
- Snapshot identifiers must not decrease during a session.
- typeServer/snapshotChanged reports the previous and new snapshot identifiers.
- Requests that include a stale snapshot should fail with a JSON-RPC error that lets the client retry with a fresh snapshot. LSP's ServerCancelled error code (-32802) is the preferred error for this case.
TSP follows LSP position conventions:
- Lines are zero-based.
- Character offsets are zero-based UTF-16 code units.
- Ranges identify source spans using a start position and end position.
If a type server stores source locations in another encoding, it must convert locations at the protocol boundary. Incorrect conversion can cause the client to request information for the wrong syntax node.
The type-query requests (typeServer/getComputedType, typeServer/getDeclaredType, typeServer/getExpectedType) identify a source construct with an arg that is either a node or a declaration. A node is a URI plus a source range. A declaration describes where and how a symbol is defined and is either a regular declaration, which is backed by a source AST node, or a synthesized declaration, which is created by the type checker and has no source node.
InvalidHandle is -1 and represents an invalid or unavailable handle. Clients and servers should treat it as a sentinel value, not as a valid object identifier.
Type results are JSON-serializable tagged objects. Each type includes a discriminator that tells the client how to interpret the rest of the object. The protocol supports built-in types, declared types, functions, classes, unions, modules, type variables, overload sets, synthesized types, and type references.
Every type object carries a numeric kind discriminator, a numeric id, and a bitfield of flags:
Type objects are snapshot-bound, and type IDs are response-local:
- A returned type object is valid only for the snapshot used by the request that produced it.
- Type IDs are used to connect TypeReference objects to earlier type objects in the same serialized response graph.
- Type IDs are not a stable global identity for a snapshot and should not be compared across separate responses.
- Type references should be used to avoid duplicating large or recursive type graphs within one response.
The current protocol is intentionally small. The exact parameters and result shapes are defined in the protocol artifacts; the table below lists every TSP message with its direction and payload shape.
A type server should implement the messages required by the client it integrates with and return undefined only where the protocol's result type allows it.
The three type-query requests differ by which type they report for the same node or declaration:
- typeServer/getComputedType returns the type inferred from code flow. After narrowing a to int, the computed type of b in b = a + 1 is int.
- typeServer/getDeclaredType returns the type explicitly written in the source. For def foo(a: int | str), the declared type of a is int | str.
- typeServer/getExpectedType returns the type the surrounding context expects. For the call foo(4), the expected type of the argument is int | str.
Use standard JSON-RPC error responses.
Errors should include enough message detail for a client log to identify the failed request, but they should not expose local secrets or implementation-only state.
A compatible type server should verify these behaviors:
- typeServer/getSupportedProtocolVersion returns a semver string supported by the client.
- All request and notification payloads serialize and deserialize according to the protocol artifacts.
- typeServer/getSnapshot returns a non-negative snapshot and snapshots do not go backward.
- Document, configuration, and watched-file changes invalidate snapshots when they can change returned analysis data.
- Requests with stale snapshots fail with a retryable cancellation error.
- Position and range conversions use LSP zero-based UTF-16 conventions.
- Import-resolution requests return document URIs or no result according to the protocol result type.
- Type queries (computed, declared, and expected) return well-formed Type objects, or undefined, for the snapshot supplied by the client.
- Multi-connection support is advertised only when the server can serve the negotiated extra transport.
- Extra connections accept every TSP request allowed for the negot
Auto-fetched and translated by AI Atlas. All rights belong to the original author.