Browse Source

Standardize API parameters to camelCase and improve LSP client reliability

- Convert tool parameters from snake_case to camelCase for consistency
- Add file existence check in LSP client before opening files
- Fix version increment timing in LSP textDocument operations
- Optimize session token tracking using onStepFinish callback
- Add debugging logs for diagnostics troubleshooting

🤖 Generated with opencode
Co-Authored-By: opencode <[email protected]>
Dax Raad 9 months ago
parent
commit
2e938d9da1

+ 8 - 7
js/src/lsp/client.ts

@@ -51,6 +51,7 @@ export namespace LSPClient {
       log.info("textDocument/publishDiagnostics", {
         path,
       });
+      console.log(path, params);
       diagnostics.set(path, params.diagnostics);
       Bus.publish(Event.Diagnostics, { path, serverID: input.serverID });
     });
@@ -129,7 +130,9 @@ export namespace LSPClient {
       },
       notify: {
         async open(input: { path: string }) {
-          const text = await Bun.file(input.path).text();
+          const file = Bun.file(input.path);
+          if (!file.exists()) return;
+          const text = await file.text();
           const opened = files.has(input.path);
           if (!opened) {
             log.info("textDocument/didOpen", input);
@@ -140,8 +143,8 @@ export namespace LSPClient {
               textDocument: {
                 uri: `file://` + input.path,
                 languageId,
-                version: 1,
-                text: text,
+                version: ++version,
+                text,
               },
             });
             files.add(input.path);
@@ -150,11 +153,10 @@ export namespace LSPClient {
 
           log.info("textDocument/didChange", input);
           diagnostics.delete(input.path);
-          version++;
           await connection.sendNotification("textDocument/didChange", {
             textDocument: {
               uri: `file://` + input.path,
-              version,
+              version: ++version,
             },
             contentChanges: [
               {
@@ -168,7 +170,7 @@ export namespace LSPClient {
         return diagnostics;
       },
       async waitForDiagnostics(input: { path: string }) {
-        log.info("refreshing diagnostics", input);
+        log.info("waiting for diagnostics", input);
         let unsub: () => void;
         let timeout: NodeJS.Timeout;
         return await Promise.race([
@@ -184,7 +186,6 @@ export namespace LSPClient {
                 resolve();
               }
             });
-            await result.notify.open(input);
           }),
           new Promise<void>((resolve) => {
             timeout = setTimeout(() => {

+ 7 - 5
js/src/session/session.ts

@@ -162,6 +162,13 @@ export namespace Session {
       msgs.push(system);
       state().messages.set(sessionID, msgs);
       generateText({
+        onStepFinish: (step) => {
+          update(sessionID, (draft) => {
+            draft.tokens.input += step.usage.inputTokens || 0;
+            draft.tokens.output += step.usage.outputTokens || 0;
+            draft.tokens.reasoning += step.usage.reasoningTokens || 0;
+          });
+        },
         messages: convertToModelMessages([
           {
             role: "system",
@@ -293,11 +300,6 @@ export namespace Session {
     session.tokens.input += usage.inputTokens || 0;
     session.tokens.output += usage.outputTokens || 0;
     session.tokens.reasoning += usage.reasoningTokens || 0;
-    await update(sessionID, (draft) => {
-      draft.tokens.input += usage.inputTokens || 0;
-      draft.tokens.output += usage.outputTokens || 0;
-      draft.tokens.reasoning += usage.reasoningTokens || 0;
-    });
     return next;
   }
 }

+ 1 - 3
js/src/tool/diagnostics.ts

@@ -40,6 +40,7 @@ TIPS:
       : path.join(app.root, args.path);
     await LSP.file(normalized);
     const diagnostics = await LSP.diagnostics();
+    console.log(diagnostics, "diagnostics");
     const file = diagnostics[normalized];
     return {
       metadata: {
@@ -51,6 +52,3 @@ TIPS:
     };
   },
 });
-
-const x: number = "asd";
-

+ 14 - 14
js/src/tool/edit.ts

@@ -59,23 +59,23 @@ export const edit = Tool.define({
   name: "edit",
   description: DESCRIPTION,
   parameters: z.object({
-    file_path: z.string().describe("The absolute path to the file to modify"),
-    old_string: z.string().describe("The text to replace"),
-    new_string: z.string().describe("The text to replace it with"),
+    filePath: z.string().describe("The absolute path to the file to modify"),
+    oldString: z.string().describe("The text to replace"),
+    newString: z.string().describe("The text to replace it with"),
   }),
   async execute(params) {
-    if (!params.file_path) {
-      throw new Error("file_path is required");
+    if (!params.filePath) {
+      throw new Error("filePath is required");
     }
 
-    let filePath = params.file_path;
+    let filePath = params.filePath;
     if (!path.isAbsolute(filePath)) {
       filePath = path.join(process.cwd(), filePath);
     }
 
     await (async () => {
-      if (params.old_string === "") {
-        await Bun.write(filePath, params.new_string);
+      if (params.oldString === "") {
+        await Bun.write(filePath, params.newString);
         return;
       }
 
@@ -95,21 +95,21 @@ export const edit = Tool.define({
         );
 
       const content = await file.text();
-      const index = content.indexOf(params.old_string);
+      const index = content.indexOf(params.oldString);
       if (index === -1)
         throw new Error(
-          `old_string not found in file. Make sure it matches exactly, including whitespace and line breaks`,
+          `oldString not found in file. Make sure it matches exactly, including whitespace and line breaks`,
         );
-      const lastIndex = content.lastIndexOf(params.old_string);
+      const lastIndex = content.lastIndexOf(params.oldString);
       if (index !== lastIndex)
         throw new Error(
-          `old_string appears multiple times in the file. Please provide more context to ensure a unique match`,
+          `oldString appears multiple times in the file. Please provide more context to ensure a unique match`,
         );
 
       const newContent =
         content.substring(0, index) +
-        params.new_string +
-        content.substring(index + params.old_string.length);
+        params.newString +
+        content.substring(index + params.oldString.length);
 
       await file.write(newContent);
     })();

+ 3 - 3
js/src/tool/grep.ts

@@ -274,7 +274,7 @@ export const grep = Tool.define({
         'File pattern to include in the search (e.g. "*.js", "*.{ts,tsx}")',
       )
       .optional(),
-    literal_text: z
+    literalText: z
       .boolean()
       .describe(
         "If true, the pattern will be treated as literal text with special regex characters escaped. Default is false.",
@@ -289,8 +289,8 @@ export const grep = Tool.define({
     const app = await App.use();
     const searchPath = params.path || app.root;
 
-    // If literal_text is true, escape the pattern
-    const searchPattern = params.literal_text
+    // If literalText is true, escape the pattern
+    const searchPattern = params.literalText
       ? escapeRegexPattern(params.pattern)
       : params.pattern;
 

+ 7 - 7
js/src/tool/patch.ts

@@ -34,7 +34,7 @@ CRITICAL REQUIREMENTS FOR USING THIS TOOL:
 The tool will apply all changes in a single atomic operation.`;
 
 const PatchParams = z.object({
-  patch_text: z
+  patchText: z
     .string()
     .describe("The full patch text that describes all changes to be made"),
 });
@@ -269,13 +269,13 @@ export const patch = Tool.define({
   name: "patch",
   description: DESCRIPTION,
   parameters: PatchParams,
-  execute: async ({ patch_text }) => {
-    if (!patch_text) {
-      throw new Error("patch_text is required");
+  execute: async (params) => {
+    if (!params.patchText) {
+      throw new Error("patchText is required");
     }
 
     // Identify all files needed for the patch and verify they've been read
-    const filesToRead = identifyFilesNeeded(patch_text);
+    const filesToRead = identifyFilesNeeded(params.patchText);
     for (const filePath of filesToRead) {
       let absPath = filePath;
       if (!path.isAbsolute(absPath)) {
@@ -309,7 +309,7 @@ export const patch = Tool.define({
     }
 
     // Check for new files to ensure they don't already exist
-    const filesToAdd = identifyFilesAdded(patch_text);
+    const filesToAdd = identifyFilesAdded(params.patchText);
     for (const filePath of filesToAdd) {
       let absPath = filePath;
       if (!path.isAbsolute(absPath)) {
@@ -343,7 +343,7 @@ export const patch = Tool.define({
     }
 
     // Process the patch
-    const [patch, fuzz] = textToPatch(patch_text, currentFiles);
+    const [patch, fuzz] = textToPatch(params.patchText, currentFiles);
     if (fuzz > 3) {
       throw new Error(
         `patch contains fuzzy matches (fuzz level: ${fuzz}). Please make your context lines more precise`,

+ 2 - 2
js/src/tool/view.ts

@@ -44,7 +44,7 @@ export const view = Tool.define({
   name: "view",
   description: DESCRIPTION,
   parameters: z.object({
-    file_path: z.string().describe("The path to the file to read"),
+    filePath: z.string().describe("The path to the file to read"),
     offset: z
       .number()
       .describe("The line number to start reading from (0-based)")
@@ -55,7 +55,7 @@ export const view = Tool.define({
       .optional(),
   }),
   async execute(params) {
-    let filePath = params.file_path;
+    let filePath = params.filePath;
     if (!path.isAbsolute(filePath)) {
       filePath = path.join(process.cwd(), filePath);
     }