Skip to content

Commit

Permalink
Merge pull request #85 from microsoft/don/issueReporter
Browse files Browse the repository at this point in the history
Support for issue reporter
  • Loading branch information
DonJayamanne authored Oct 31, 2024
2 parents 2e498bd + 3f20ff1 commit f841dbe
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 15 deletions.
9 changes: 9 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,22 @@
"icon": "$(copilot)",
"title": "%commands.dachat.analyzeCsv.title%",
"shortTitle": "%commands.dachat.analyzeCsv.shortTitle%"
},
{
"category": "Data Analysis",
"command": "dachat.reportIssue",
"title": "Report Issue..."
}
],
"menus": {
"commandPalette": [
{
"command": "dachat.analyzeCsv",
"when": "false"
},
{
"command": "dachat.reportIssue",
"when": "true"
}
],
"editor/title": [
Expand Down
2 changes: 2 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import * as vscode from 'vscode';
import { registerCsvCommand } from './csvCommand';
import { DataAgent } from './dataAgent';
import { registerIssueReporter } from './issueReporter';
import { initializeLogger } from './logger';
import { FindFilesTool, InstallPythonPackageTool, RunPythonTool } from './tools';

Expand All @@ -14,6 +15,7 @@ export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(logger);
context.subscriptions.push(dataAgent);
context.subscriptions.push(registerCsvCommand());
context.subscriptions.push(registerIssueReporter(context));
context.subscriptions.push(vscode.lm.registerTool(FindFilesTool.Id, new FindFilesTool(context)));
const pythonTool = new RunPythonTool(context);
context.subscriptions.push(vscode.lm.registerTool(RunPythonTool.Id, pythonTool));
Expand Down
70 changes: 70 additions & 0 deletions src/issueReporter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation and GitHub. All rights reserved.
*--------------------------------------------------------------------------------------------*/

import { commands, ExtensionContext } from 'vscode';
import { getLastErrors } from './logger';

export function registerIssueReporter(context: ExtensionContext) {
return commands.registerCommand('dachat.reportIssue', () => {
commands.executeCommand('workbench.action.openIssueReporter', {
extensionId: context.extension.id,
issueBody: issueBody,
data: getIssueData()
});
});
}

const issueBody = `
<!-- Please fill in all XXX markers -->
# Behaviour
XXX
## Steps to reproduce:
1. XXX
<!--
**After** creating the issue on GitHub, you can add screenshots and GIFs of what is happening.
Consider tools like https://gifcap.dev, https://www.screentogif.com/ for GIF creation.
-->
<!-- **NOTE**: Please do provide logs from Data Analysis Output panel. -->
<!-- Use the command \`Output: Focus on Output View\`, select \`Data Analysis\` from the dropdown -->
<!-- Copy the output and past it in the XXX region -->
# Outputs
<details>
<summary>Output from Data Analysis Output Panel</summary>
<p>
\`\`\`
XXX
\`\`\`
</p>
</details>
`;


function getIssueData() {
const error = getLastErrors().trim();
if (!error) {
return '';
}
return `
<details>
<summary>Last few Errors</summary>
<p>
\`\`\`
${error}
\`\`\`
</p>
</details>
`;
};
31 changes: 30 additions & 1 deletion src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@
*--------------------------------------------------------------------------------------------*/

import { ExtensionContext, ExtensionMode, LogOutputChannel, window } from "vscode";
import { StopWatch } from "./platform/common/stopwatch";

let logger: LogOutputChannel;

const lastSeenError = {
timer: new StopWatch(),
error: ''
}

export function initializeLogger(extensionContext: ExtensionContext) {
if (!logger) {
logger = window.createOutputChannel('Data Analysis', { log: true });
Expand All @@ -17,9 +23,32 @@ export function initializeLogger(extensionContext: ExtensionContext) {

debug.bind(logger)(message, ...args);
};
const error = logger.error;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
logger.error = (errorMsg: string | Error, ...args: any[]) => {
// Get track of the last known error for issue reporting purposes.
lastSeenError.timer.reset();
lastSeenError.error = [`${getTime()} ${errorMsg.toString()}`].concat(args.map(arg => `${arg}`)).join('\n');
error.bind(logger)(errorMsg, ...args);
}
}

return logger;
}

export { logger };

function getTime() {
const now = new Date();
return now.toTimeString().split(' ')[0];
}

function getLastErrors() {
// If we haven't see any errors in the past 20 minutes, no point reporting any old errors.
if (!lastSeenError.error || lastSeenError.timer.elapsedTime > 20 * 60 * 1000) {
return '';
}
return lastSeenError.error;
}

export { getLastErrors, logger };

17 changes: 17 additions & 0 deletions src/platform/common/stopwatch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation and GitHub. All rights reserved.
*--------------------------------------------------------------------------------------------*/


/**
* Tracks wall clock time. Start time is set at contruction.
*/
export class StopWatch {
private started = Date.now();
public get elapsedTime() {
return Date.now() - this.started;
}
public reset() {
this.started = Date.now();
}
}
23 changes: 9 additions & 14 deletions src/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class RunPythonTool implements vscode.LanguageModelTool<IRunPythonParamet
// eslint-disable-next-line @typescript-eslint/no-explicit-any
error: (message: string, ...args: any[]) => logger.error(`Pyodide => ${message}`, ...args),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
info: (message: string, ...args: any[]) => logger.info(`Pyodide => ${message}`, ...args)
info: (message: string, ...args: any[]) => logger.debug(`Pyodide => ${message}`, ...args)
}
});
}
Expand All @@ -88,19 +88,13 @@ export class RunPythonTool implements vscode.LanguageModelTool<IRunPythonParamet
_token: vscode.CancellationToken
) {
const code = sanitizePythonCode(options.input.code);
logger.debug(`Executing Python Code for "${options.input.reason}"`);
logger.debug(`Code => `);
logger.debug(code);
logger.info(`Executing Python Code for "${options.input.reason || ''}"`);
logger.info(`Code => `, code);

this.pendingRequests = this.pendingRequests.finally().then(() => this._kernel.execute(code));
const result = await this.pendingRequests as Awaited<ReturnType<typeof Kernel.prototype.execute>>;

logger.debug(`Result => `);
Object.keys(result || {}).forEach(key => {
logger.debug(`${key} :`);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
logger.debug((result as any)[key]);
});
logger.debug(`Result => `, JSON.stringify(result));

const content: (vscode.LanguageModelPromptTsxPart | vscode.LanguageModelTextPart)[] = []
if (result && result['text/plain']) {
Expand All @@ -112,7 +106,9 @@ export class RunPythonTool implements vscode.LanguageModelTool<IRunPythonParamet
}

if (result && result['application/vnd.code.notebook.error']) {
throw result['application/vnd.code.notebook.error'] as Error;
const error = result['application/vnd.code.notebook.error'] as Error;
logger.error(`Toolcall failed, Error ${error.name}, ${error.message}`);
throw error;
}
return new vscode.LanguageModelToolResult(content);
}
Expand Down Expand Up @@ -188,7 +184,7 @@ export class InstallPythonPackageTool implements vscode.LanguageModelTool<IInsta
options: vscode.LanguageModelToolInvocationOptions<IInstallPythonPackage>,
token: vscode.CancellationToken
) {
logger.debug(`Installing Package "${options.input.package}"`);
logger.info(`Installing Package "${options.input.package}"`);
const result = await this.pythonTool.invoke({
input: {
code: `import ${options.input.package}`,
Expand All @@ -197,8 +193,7 @@ export class InstallPythonPackageTool implements vscode.LanguageModelTool<IInsta
tokenizationOptions: options.tokenizationOptions
}, token);

logger.debug(`Result after installing package ${options.input.package} => `);
logger.debug(JSON.stringify(result));
logger.debug(`Result after installing package ${options.input.package} => `, JSON.stringify(result));

return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart('Installation successful')]);
}
Expand Down

0 comments on commit f841dbe

Please sign in to comment.