5.2 KiB
Signature Help Tool
Summary
Add an lsp_signature_help tool that returns function/method signature information at a call site — parameter names, types, documentation, and which parameter is currently active. This complements lsp_hover (which shows type info for a symbol) and lsp_completions (which lists available members).
Motivation
When the LLM is writing a function call with multiple parameters, it needs to know the parameter order, types, and what each parameter does. Today it either:
- Calls
lsp_hoveron the function name — gets the full signature but no active-parameter context - Reads the source/docs — expensive and slow
- Guesses — risks hallucination
LSP's textDocument/signatureHelp is designed exactly for this: given a cursor position inside a call's argument list, it returns the signature with the active parameter highlighted. The lsp-pi competitor already exposes this as its signature action.
Goals
lsp_signature_helptool — return the active signature, parameters, and documentation at a call site position- Active parameter highlighting — clearly indicate which parameter the cursor is on
- Multiple overloads — when a function has overloads, show the active one and list alternatives
- Clean output — format for LLM consumption (not raw LSP JSON)
Non-goals
- Trigger character detection (e.g., auto-invoke on
(or,) — this is a query tool, not an IDE feature - Tree-sitter fallback — signature help fundamentally requires type resolution; no useful fallback possible
- Retrigger logic — the LSP retrigger context is for interactive editors; we do a single request
Design
Tool definition
lsp_signature_help
| Parameter | Type | Description |
|---|---|---|
path |
string | File path |
line |
number | Line number (1-indexed) |
character |
number | Column number (1-indexed) |
No query parameter — signature help is inherently position-based (cursor must be inside the argument list).
LSP request
const result = await client.sendRequest<SignatureHelp | null>("textDocument/signatureHelp", {
textDocument: { uri },
position: { line: params.line - 1, character: params.character - 1 },
});
Output format
Signature 1 of 2 (active):
createReadStream(path: PathLike, options?: ReadStreamOptions): ReadStream
Parameters:
→ path: PathLike — The path to the file to read
options?: ReadStreamOptions — Options for the stream (encoding, start, end, highWaterMark)
Returns: ReadStream
Signature 2 of 2:
createReadStream(path: PathLike, encoding: BufferEncoding): ReadStream
Key formatting rules:
- Show all signatures, mark the active one (
activeSignatureindex from LSP response) - For the active signature, show all parameters with the active one marked with
→ - Include parameter documentation if available (from
SignatureInformation.parameters[].documentation) - Include signature-level documentation if available (from
SignatureInformation.documentation) - Truncate long documentation to 2 lines per parameter
Handling edge cases
- No signature help available — return "No signature help available at this position. Cursor must be inside a function call's argument list."
- Empty parameters — show signature line but skip the parameters section
- Missing documentation — show parameters with types only, skip doc lines
- Multiple overloads — show all, sorted by the
activeSignaturefirst - No LSP server running — return the standard unavailable reason message
Details object
interface SignatureHelpDetails {
hasResult: boolean;
signatureCount: number;
activeSignature: number;
activeParameter: number;
}
TUI rendering
renderCall:
lsp_signature_help src/handler.ts:42:15
renderResult (collapsed):
createReadStream(path, options?) — param 2 of 2
Show the function name and active parameter position. If no result, show "No signature help" in dim.
File layout
src/tools/
└── signature-help.ts
Integration
- Register in
index.tsalongside existing tools - Add to system prompt snippet: "Use
lsp_signature_helpwhen you need to know the parameter order or types for a function call" - No tree-sitter fallback — return clear message when no LSP is available
Open questions
- Naming —
lsp_signature_helpvslsp_signaturevslsp_params? The LSP protocol calls it "signature help" solsp_signature_helpis most precise, but it's verbose. The competitor usessignature(as an action on the unified tool). Going withlsp_signature_helpfor consistency withlsp_diagnostics,lsp_definition, etc. - Context parameter — should we accept an optional
contextwithtriggerKindandtriggerCharacter? Probably not — the LLM doesn't know or care about trigger characters. Always sendtriggerKind: Invoked. - Interaction with completions — when the LLM is inside a call and wants to know the expected type for the current argument, should it use signature help (to see the parameter type) then completions (to see what values match)? The system prompt should guide this workflow.