Skip to content

Commit e5631f0

Browse files
committed
feat(vscode): add language model tool to get the library and resource imports from a robot file
1 parent 7f46a6b commit e5631f0

File tree

6 files changed

+305
-33
lines changed

6 files changed

+305
-33
lines changed

package.json

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1941,16 +1941,14 @@
19411941
]
19421942
}
19431943
],
1944-
"chatParticipants":[
1945-
1946-
],
1944+
"chatParticipants": [],
19471945
"languageModelTools": [
19481946
{
1949-
"name": "robot-get_library_doc",
1947+
"name": "robot-get_library_documentation",
19501948
"displayName": "Get Library Documentation",
1951-
"toolReferenceName": "robotGetLibraryDoc",
1952-
"modelDescription": "Gets the library documentation for the given library name. This includes keywords, documentation, and other information about the library.",
1953-
"userDescription": "Gets documentation for the given library.",
1949+
"toolReferenceName": "robotGetLibraryDocumentation",
1950+
"modelDescription": "Retrieves comprehensive documentation for Robot Framework libraries. Returns the library's description, initialization parameters with their types and default values, complete list of available keywords with their signatures (including arguments, types, and return values). Use this tool when you need to understand what keywords are available in a library, how to initialize it, or get detailed parameter information. Do not use for getting documentation of specific keywords (use robot-get_keyword_documentation instead) or for analyzing test files. Limitations: Only works with libraries that are properly installed and importable in the current Python environment, may not work with dynamic libraries that change behavior based on runtime conditions, and requires the specified library to be accessible from the workspace's Robot Framework configuration.",
1951+
"userDescription": "Gets Documentation and keyword list for a Robot Framework library.",
19541952
"canBeReferencedInPrompt": true,
19551953
"tags": [
19561954
"robot",
@@ -1977,11 +1975,75 @@
19771975
}
19781976
}
19791977
},
1978+
{
1979+
"name": "robot-get_keyword_documentation",
1980+
"displayName": "Get Keyword Documentation",
1981+
"toolReferenceName": "robotGetKeywordDoc",
1982+
"modelDescription": "Retrieves detailed documentation for a specific Robot Framework keyword. Returns the keyword's complete signature with parameter names, types, default values, and detailed descriptions, along with return value information and usage examples. Use this tool when you need specific information about how to use a particular keyword, its parameters, or expected behavior. Do not use for getting a list of all keywords in a library (use robot-get_library_documentation instead) or for analyzing test file content. Limitations: Requires both the keyword name and library name to be specified accurately, only works with keywords from libraries that are properly installed and importable in the current Python environment, may not work with dynamic keywords that change behavior based on runtime conditions, and requires the specified library to be accessible from the workspace's Robot Framework configuration.",
1983+
"userDescription": "Gets detailed documentation for a specific Robot Framework keyword.",
1984+
"canBeReferencedInPrompt": true,
1985+
"tags": [
1986+
"robot",
1987+
"robotframework",
1988+
"robotframework-keyword",
1989+
"robotcode"
1990+
],
1991+
"icon": "$(robotcode-robot)",
1992+
"inputSchema": {
1993+
"type": "object",
1994+
"required": [
1995+
"keywordName",
1996+
"libraryName"
1997+
],
1998+
"properties": {
1999+
"keywordName": {
2000+
"type": "string",
2001+
"description": "The name of the keyword."
2002+
},
2003+
"libraryName": {
2004+
"type": "string",
2005+
"description": "The name of the library containing the keyword."
2006+
},
2007+
"resourcePath": {
2008+
"type": "string",
2009+
"description": "The path to the robot framework file or workspace."
2010+
}
2011+
}
2012+
}
2013+
},
2014+
{
2015+
"name": "robot-get_document_imports",
2016+
"displayName": "Get Document Imports",
2017+
"toolReferenceName": "robotGetDocumentImports",
2018+
"modelDescription": "Retrieves a list of all imported libraries and resource files for a specific Robot Framework document. Returns the names and paths of all libraries imported in the specified Robot Framework file. Use this tool when you need to analyze the dependencies of a Robot Framework document or understand its library and resource usage. Limitations: Only works with Robot Framework files, may not detect dynamic imports or libraries loaded at runtime, and requires the specified file to be accessible from the workspace's Robot Framework configuration.",
2019+
"userDescription": "Gets a list of all imported libraries and resources for a specific Robot Framework document.",
2020+
"canBeReferencedInPrompt": true,
2021+
"tags": [
2022+
"robot",
2023+
"robotframework",
2024+
"robotframework-library",
2025+
"robotframework-resource",
2026+
"robotcode"
2027+
],
2028+
"icon": "$(robotcode-robot)",
2029+
"inputSchema": {
2030+
"type": "object",
2031+
"required": [
2032+
"resourcePath"
2033+
],
2034+
"properties": {
2035+
"resourcePath": {
2036+
"type": "string",
2037+
"description": "The path to a robot framework file."
2038+
}
2039+
}
2040+
}
2041+
},
19802042
{
19812043
"name": "robot-get_environment_details",
19822044
"displayName": "Get Robot Framework Environment Informations",
19832045
"toolReferenceName": "robotGetEnvironmentInfo",
1984-
"modelDescription": "This tool will retrieve the details of the Robot Framework Environment for the specified file or workspace. This includes informations about the python interpreter, like the version and the executable path, and the versions of robot framework, RobotCode, robocop and robotidy if installed.",
2046+
"modelDescription": "Retrieves detailed environment information for Robot Framework workspaces or files. Returns comprehensive details about the Python interpreter (version, executable path), installed Robot Framework version, RobotCode extension version, and optional tool versions (robocop, robotidy) if available. Use this tool when you need to diagnose environment issues, verify installations, check version compatibility, or troubleshoot Robot Framework setup problems. Limitations: Only provides information about the currently configured Python environment for the workspace, may not detect tools installed in different Python environments, requires proper workspace configuration to access environment details, and information accuracy depends on the current RobotCode language server connection.",
19852047
"userDescription": "Gets informations about the Robot Framework Environment.",
19862048
"canBeReferencedInPrompt": true,
19872049
"tags": [

packages/language_server/src/robotcode/language_server/robotframework/parts/keywords_treeview.py

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@
1717
@dataclass(repr=False)
1818
class GetDocumentImportsParams(CamelSnakeMixin):
1919
text_document: TextDocumentIdentifier
20+
no_documentation: Optional[bool] = None
21+
22+
23+
@dataclass(repr=False)
24+
class GetDocumentKeywordsParams(CamelSnakeMixin):
25+
text_document: TextDocumentIdentifier
26+
no_documentation: Optional[bool] = None
2027

2128

2229
@dataclass(repr=False)
@@ -25,6 +32,13 @@ class GetLibraryDocumentationParams(CamelSnakeMixin):
2532
library_name: str
2633

2734

35+
@dataclass(repr=False)
36+
class GetKeywordDocumentationParams(CamelSnakeMixin):
37+
workspace_folder_uri: str
38+
library_name: str
39+
keyword_name: str
40+
41+
2842
@dataclass(repr=False)
2943
class Keyword(CamelSnakeMixin):
3044
name: str
@@ -69,6 +83,7 @@ def __init__(self, parent: "RobotLanguageServerProtocol") -> None:
6983
def _get_document_imports(
7084
self,
7185
text_document: TextDocumentIdentifier,
86+
no_documentation: Optional[bool] = None,
7287
*args: Any,
7388
**kwargs: Any,
7489
) -> Optional[List[DocumentImport]]:
@@ -87,16 +102,18 @@ def _get_document_imports(
87102
alias=v.alias,
88103
id=str(hash(v)),
89104
type="library",
90-
documentation=v.library_doc.to_markdown(add_signature=False),
105+
documentation=v.library_doc.to_markdown(add_signature=False) if not no_documentation else None,
91106
keywords=[
92107
Keyword(
93108
l.name,
94109
str(hash(l)),
95110
l.parameter_signature(),
96-
l.to_markdown(add_signature=False),
111+
l.to_markdown(add_signature=False) if not no_documentation else None,
97112
)
98113
for l in v.library_doc.keywords.values()
99-
],
114+
]
115+
if not no_documentation
116+
else None,
100117
)
101118
)
102119
for _k, v in namespace.get_resources().items():
@@ -106,21 +123,29 @@ def _get_document_imports(
106123
alias=None,
107124
id=str(hash(v)),
108125
type="resource",
109-
documentation=v.library_doc.to_markdown(add_signature=False),
126+
documentation=v.library_doc.to_markdown(add_signature=False) if not no_documentation else None,
110127
keywords=[
111-
Keyword(l.name, str(hash(l)), l.parameter_signature(), l.to_markdown(add_signature=False))
128+
Keyword(
129+
l.name,
130+
str(hash(l)),
131+
l.parameter_signature(),
132+
l.to_markdown(add_signature=False) if not no_documentation else None,
133+
)
112134
for l in v.library_doc.keywords.values()
113-
],
135+
]
136+
if not no_documentation
137+
else None,
114138
)
115139
)
116140

117141
return result
118142

119-
@rpc_method(name="robot/keywordsview/getDocumentKeywords", param_type=GetDocumentImportsParams, threaded=True)
143+
@rpc_method(name="robot/keywordsview/getDocumentKeywords", param_type=GetDocumentKeywordsParams, threaded=True)
120144
@_logger.call
121145
def _get_document_keywords(
122146
self,
123147
text_document: TextDocumentIdentifier,
148+
no_documentation: Optional[bool] = None,
124149
*args: Any,
125150
**kwargs: Any,
126151
) -> Optional[List[Keyword]]:
@@ -131,7 +156,12 @@ def _get_document_keywords(
131156
namespace = self.parent.documents_cache.get_namespace(document)
132157

133158
return [
134-
Keyword(l.name, str(hash(l)), l.parameter_signature(), l.to_markdown(add_signature=False))
159+
Keyword(
160+
l.name,
161+
str(hash(l)),
162+
l.parameter_signature(),
163+
l.to_markdown(add_signature=False) if not no_documentation else None,
164+
)
135165
for l in namespace.get_library_doc().keywords.values()
136166
]
137167

@@ -220,3 +250,32 @@ def _get_library_documentation(
220250
for s in libdoc.inits.values()
221251
],
222252
)
253+
254+
@rpc_method(
255+
name="robot/keywordsview/getKeywordDocumentation", param_type=GetKeywordDocumentationParams, threaded=True
256+
)
257+
@_logger.call
258+
def _get_keyword_documentation(
259+
self,
260+
workspace_folder_uri: str,
261+
library_name: str,
262+
keyword_name: str,
263+
*args: Any,
264+
**kwargs: Any,
265+
) -> Optional[Keyword]:
266+
imports_manager = self.parent.documents_cache.get_imports_manager_for_uri(Uri(workspace_folder_uri))
267+
268+
libdoc = imports_manager.get_libdoc_for_library_import(library_name, (), ".")
269+
if libdoc.errors:
270+
raise ValueError(f"Errors while loading library documentation: {libdoc.errors}")
271+
272+
kw = libdoc.keywords.get(keyword_name, None)
273+
if kw is None:
274+
raise ValueError(f"Keyword '{keyword_name}' not found in library '{library_name}'.")
275+
276+
return Keyword(
277+
name=kw.name,
278+
id=str(hash(kw)),
279+
signature=kw.parameter_signature(),
280+
documentation=kw.to_markdown(),
281+
)

vscode-client/extension/index.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { KeywordsTreeViewProvider } from "./keywordsTreeViewProvider";
77
import { LanguageToolsManager } from "./languageToolsManager";
88
import { NotebookManager } from "./notebook";
99
import path from "path";
10-
import { GetEnvironmentDetails, GetLibDocTool } from "./lmTools";
10+
import { GetDocumentImportsTool, GetEnvironmentDetails, GetKeywordInfoTool, GetLibraryInfoTool } from "./lmTools";
1111

1212
class TerminalLink extends vscode.TerminalLink {
1313
constructor(
@@ -154,7 +154,18 @@ export async function activateAsync(context: vscode.ExtensionContext): Promise<v
154154
}, 1000);
155155
}
156156
}),
157-
vscode.lm.registerTool("robot-get_library_doc", new GetLibDocTool(context, languageClientManger, outputChannel)),
157+
vscode.lm.registerTool(
158+
"robot-get_library_documentation",
159+
new GetLibraryInfoTool(context, languageClientManger, outputChannel),
160+
),
161+
vscode.lm.registerTool(
162+
"robot-get_keyword_documentation",
163+
new GetKeywordInfoTool(context, languageClientManger, outputChannel),
164+
),
165+
vscode.lm.registerTool(
166+
"robot-get_document_imports",
167+
new GetDocumentImportsTool(context, languageClientManger, outputChannel),
168+
),
158169
vscode.lm.registerTool(
159170
"robot-get_environment_details",
160171
new GetEnvironmentDetails(context, languageClientManger, outputChannel),

vscode-client/extension/keywordsTreeViewProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ export class KeywordsTreeViewProvider
196196
const currentDoc = document; // needed for the closure
197197

198198
this._currentDocumentData.imports = (
199-
await this.languageClientsManager.getDocumentImports(document, this._cancelationSource.token)
199+
await this.languageClientsManager.getDocumentImports(document, false, this._cancelationSource.token)
200200
)
201201
.map((lib_or_res) => {
202202
if (this._cancelationSource?.token.isCancellationRequested) {

vscode-client/extension/languageclientsmanger.ts

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export interface LibraryDocumentation {
4747
name: string;
4848
documentation?: string;
4949
keywords?: Keyword[];
50-
initializers?: DocumentImport[];
50+
initializers?: Keyword[];
5151
}
5252

5353
export interface DocumentImport {
@@ -892,18 +892,27 @@ export class LanguageClientsManager {
892892
}
893893

894894
public async getDocumentImports(
895-
document: vscode.TextDocument,
895+
document_or_uri: vscode.TextDocument | vscode.Uri | string,
896+
noDocumentation?: boolean | undefined,
896897
token?: vscode.CancellationToken | undefined,
897898
): Promise<DocumentImport[]> {
898-
const client = await this.getLanguageClientForResource(document.uri);
899+
const uri =
900+
document_or_uri instanceof vscode.Uri
901+
? document_or_uri
902+
: typeof document_or_uri === "string"
903+
? vscode.Uri.parse(document_or_uri)
904+
: document_or_uri.uri;
905+
906+
const client = await this.getLanguageClientForResource(uri);
899907

900908
if (!client) return [];
901909

902910
return (
903911
(await client.sendRequest<DocumentImport[]>(
904912
"robot/keywordsview/getDocumentImports",
905913
{
906-
textDocument: { uri: document.uri.toString() },
914+
textDocument: { uri: uri.toString() },
915+
noDocumentation: noDocumentation,
907916
},
908917
token ?? new vscode.CancellationTokenSource().token,
909918
)) ?? []
@@ -931,6 +940,29 @@ export class LanguageClientsManager {
931940
);
932941
}
933942

943+
public async getKeywordDocumentation(
944+
workspace_folder: vscode.WorkspaceFolder,
945+
libraryName: string,
946+
keywordName: string,
947+
token?: vscode.CancellationToken | undefined,
948+
): Promise<Keyword | undefined> {
949+
const client = await this.getLanguageClientForResource(workspace_folder.uri);
950+
951+
if (!client) return undefined;
952+
953+
return (
954+
(await client.sendRequest<Keyword>(
955+
"robot/keywordsview/getKeywordDocumentation",
956+
{
957+
workspaceFolderUri: workspace_folder.uri.toString(),
958+
libraryName: libraryName,
959+
keywordName: keywordName,
960+
},
961+
token ?? new vscode.CancellationTokenSource().token,
962+
)) ?? undefined
963+
);
964+
}
965+
934966
public async getDocumentKeywords(
935967
document: vscode.TextDocument,
936968
token?: vscode.CancellationToken | undefined,

0 commit comments

Comments
 (0)