@@ -39,6 +39,24 @@ function toResult(data: unknown): vscode.LanguageModelToolResult {
3939 ] ) ;
4040}
4141
42+ function getResponseCharCount ( data : unknown ) : number {
43+ return typeof data === "string" ? data . length : JSON . stringify ( data , null , 2 ) . length ;
44+ }
45+
46+ function getToolErrorCode ( error : unknown ) : string {
47+ const message = error instanceof Error ? error . message : String ( error ) ;
48+ if ( message . includes ( "No workspace folder" ) ) {
49+ return "noWorkspaceFolder" ;
50+ }
51+ if ( message . includes ( "Unsupported URI scheme" ) ) {
52+ return "unsupportedUriScheme" ;
53+ }
54+ if ( message . includes ( "outside the current workspace" ) ) {
55+ return "outsideWorkspace" ;
56+ }
57+ return "unexpectedError" ;
58+ }
59+
4260/**
4361 * Resolve a file path to a vscode.Uri.
4462 * Accepts:
@@ -97,38 +115,49 @@ const fileStructureTool: vscode.LanguageModelTool<FileStructureInput> = {
97115 const startTime = Date . now ( ) ;
98116 let resultCount = 0 ;
99117 let status = "success" ;
100- let errorMessage = "" ;
118+ let errorCode = "" ;
119+ let emptyReason = "" ;
120+ let responseCharCount = 0 ;
101121 try {
102122 const uri = resolveFileUri ( options . input . uri ) ;
103123 try {
104124 await vscode . workspace . fs . stat ( uri ) ;
105125 } catch {
106126 status = "error" ;
107- errorMessage = `File not found: ${ vscode . workspace . asRelativePath ( uri ) } ` ;
108- return toResult ( { error : errorMessage } ) ;
127+ errorCode = "fileNotFound" ;
128+ const fileNotFoundPayload = { error : "File not found." } ;
129+ responseCharCount = getResponseCharCount ( fileNotFoundPayload ) ;
130+ return toResult ( fileNotFoundPayload ) ;
109131 }
110132 const symbols = await vscode . commands . executeCommand < vscode . DocumentSymbol [ ] > (
111133 "vscode.executeDocumentSymbolProvider" , uri ,
112134 ) ;
113135 if ( ! symbols || symbols . length === 0 ) {
114136 status = "empty" ;
115- return toResult ( { error : "No symbols found. The file may not be recognized by the Java language server." } ) ;
137+ emptyReason = "documentSymbolProviderEmpty" ;
138+ const noSymbolsPayload = { error : "No symbols found. The file may not be recognized by the Java language server." } ;
139+ responseCharCount = getResponseCharCount ( noSymbolsPayload ) ;
140+ return toResult ( noSymbolsPayload ) ;
116141 }
117142 const counter = { count : 0 } ;
118143 const result = symbolsToJson ( symbols , 0 , counter ) ;
119- const truncated = counter . count >= MAX_SYMBOL_NODES ;
120144 resultCount = counter . count ;
121- return toResult ( { symbols : result , ...( truncated && { truncated : true } ) } ) ;
145+ const truncated = counter . count >= MAX_SYMBOL_NODES ;
146+ const fileStructurePayload = { symbols : result , ...( truncated && { truncated : true } ) } ;
147+ responseCharCount = getResponseCharCount ( fileStructurePayload ) ;
148+ return toResult ( fileStructurePayload ) ;
122149 } catch ( e ) {
123150 status = "error" ;
124- errorMessage = e instanceof Error ? e . message : String ( e ) ;
151+ errorCode = errorCode || getToolErrorCode ( e ) ;
125152 throw e ;
126153 } finally {
127154 sendInfo ( "" , {
128155 operationName : "lmTool.getFileStructure" ,
129156 status,
130- ...( errorMessage && { errorMessage } ) ,
157+ ...( errorCode && { errorCode } ) ,
158+ ...( emptyReason && { emptyReason } ) ,
131159 resultCount,
160+ responseCharCount,
132161 durationMs : Date . now ( ) - startTime ,
133162 } ) ;
134163 }
@@ -179,34 +208,47 @@ const findSymbolTool: vscode.LanguageModelTool<FindSymbolInput> = {
179208 async invoke ( options , _token ) {
180209 const startTime = Date . now ( ) ;
181210 let resultCount = 0 ;
211+ let totalResults = 0 ;
212+ const limit = Math . min ( Math . max ( options . input . limit || 20 , 1 ) , 50 ) ;
182213 let status = "success" ;
183- let errorMessage = "" ;
214+ let errorCode = "" ;
215+ let emptyReason = "" ;
216+ let responseCharCount = 0 ;
184217 try {
185218 const symbols = await vscode . commands . executeCommand < vscode . SymbolInformation [ ] > (
186219 "vscode.executeWorkspaceSymbolProvider" , options . input . query ,
187220 ) ;
188221 if ( ! symbols || symbols . length === 0 ) {
189222 status = "empty" ;
190- return toResult ( { results : [ ] , message : `No symbols matching '${ options . input . query } ' found.` } ) ;
223+ emptyReason = "workspaceSymbolNoMatch" ;
224+ const noMatchesPayload = { results : [ ] , message : "No symbols found." } ;
225+ responseCharCount = getResponseCharCount ( noMatchesPayload ) ;
226+ return toResult ( noMatchesPayload ) ;
191227 }
192- const limit = Math . min ( Math . max ( options . input . limit || 20 , 1 ) , 50 ) ;
228+ totalResults = symbols . length ;
193229 const results = symbols . slice ( 0 , limit ) . map ( s => ( {
194230 name : s . name ,
195231 kind : vscode . SymbolKind [ s . kind ] ,
196232 location : `${ vscode . workspace . asRelativePath ( s . location . uri ) } :${ s . location . range . start . line + 1 } ` ,
197233 } ) ) ;
198234 resultCount = results . length ;
199- return toResult ( { results, total : symbols . length } ) ;
235+ const findSymbolPayload = { results, total : symbols . length } ;
236+ responseCharCount = getResponseCharCount ( findSymbolPayload ) ;
237+ return toResult ( findSymbolPayload ) ;
200238 } catch ( e ) {
201239 status = "error" ;
202- errorMessage = e instanceof Error ? e . message : String ( e ) ;
240+ errorCode = getToolErrorCode ( e ) ;
203241 throw e ;
204242 } finally {
205243 sendInfo ( "" , {
206244 operationName : "lmTool.findSymbol" ,
207245 status,
208- ...( errorMessage && { errorMessage } ) ,
246+ ...( errorCode && { errorCode } ) ,
247+ ...( emptyReason && { emptyReason } ) ,
248+ limit,
209249 resultCount,
250+ totalResults,
251+ responseCharCount,
210252 durationMs : Date . now ( ) - startTime ,
211253 } ) ;
212254 }
0 commit comments