AIアシスタンスでESLint違反を修正する方法

この進行中の Docker Labs GenAI シリーズ AI開発者ツールのエキサイティングな空間を探求します。 Dockerでは、誇大広告を使わずにオープンに探求できる広大な範囲があると信じています。 私たちは探索を共有し、開発者コミュニティとリアルタイムで協力します。 開発者はGitHub Copilotなどのオートコンプリートツールを採用し、チャットを使用していますが、AIツールには、ソフトウェアライフサイクル全体を通じて、より具体的なタスクやインターフェイスを支援する大きな可能性があります。 したがって、私たちの探求は広範囲になります。 私たちはオープンソースとしてリリースしますので、あなたも私たちと一緒にプレイし、探索し、ハックすることができます。

このシリーズの前回の記事では、リンターについて説明し、AI アシスタントを使用して ESLint を実行する方法について説明しました。この投稿では、AI支援による違反の解決について説明します。 

2400x1260 Docker Labs Genai

AIアシスタントがエディターまたはGitを介して違反に対してアクションを実行する前に(図 1)、まず質問に答える必要があります:LLMは適切な知識とツールを使用してESLint違反の解決策を生成できますか?

この記事を、eslint によって検出された違反を修正するために ai を使用するコンテキストに配置する図です。
図 1: ESLint 違反の修正。
Fix any lint violations you can in my project.

ESLint 違反

違反を解決するために、LLM は linter からの違反に関する情報と、それを引き起こしているソース コードに関するコンテキストが必要です。 また、ある程度の人間による監督も必要かもしれません。 モデルはコンテキスト ウィンドウを制限し、より少ないコンテキストでより良い結果を生成するため、コンテキストを縮小するように最適化する必要があります。 このことから、「糸くずの侵害を解決するために必要な最小限のコンテキストと監視はどれくらいか」と疑問に思います。

たとえば、人間の指示がなければ、アシスタントは括弧のバランスをとる方法を知ることができません。

// export const dockerfileRegex = new RegExp('(.*\\.?Dockerfile', 'i');
// Goal: new RegExp('(.*)\\.?Dockerfile', 'i');

Your `dockerfileRegex` regular expression is currently unterminated. This means the group you started at `(.*\\.?Dockerfile` doesn't have an ending bracket. Here is a fixed version of it:
```typescript
export const dockerfileRegex = new RegExp('(.*\\.?Dockerfile)', 'i');
```
I added a ")" to close the group.

特定の違反に焦点を当てる

ESLint ルールのリストを LLM が支援できる違反に絞り込みたいと考えています。

図 2では、次のようなすべての ESLint ルールをまとめました。

  • 推奨されます
  • ESLint 自体で自動修正できません

そして、次のようなルールが必要です。

  • 合理的な修正を行うために監督を必要としないでください。
コンテキストと監督要件を示すテキスト リスト (例: "修正を行うにはソース コードが必要ですか?" ") は、違反のグループを特定するのに役立ちます。
テキストと、llm が役立つ違反のルール (違反、コンテキスト、監督など) を指定する表を示すスクリーンショット。
図 2: LLM が支援できる違反。

このコンテキストでは、合計 4 つの違反グループが生成されます。

グループ 1 (周囲のソースコードからのコンテキストや監督は必要ありません。 スクリプトを適用して、これらの違反を修正できます。

グループ2 (周囲のソース コードからのコンテキストは必要ありませんが、これらは間違いであるため、LLM がコードの一部を評価する必要がある可能性があります。LLM はこれらの違反を解決するためのスクリプトを生成できますが、違反は間違いであると仮定します。 LLM が単独で評価できる違反がいくつかあります。

グループ3 (周囲のソースコードからのコンテキストが必要ですが、監視は必要ありません。これは、LLMが支援を提供する絶好の機会です。 ツールを使って、適切なコンテキストを取り入れることができます。

グループ4 (周囲のソースコードからのコンテキストが必要であり、監督が必要な場合があります。

  • 無効な正規表現
  • 安全でないオプションのチェーン
  • 一定の条件

正確な状況に大きく依存しますが、LLMは役立つかもしれませんか?

ありがたいことに、ほぼすべての違反には、監督なしで合理的な修正を適用することができました。 これらは、私たちが焦点を当てる違反です。

初期プロンプト

まず、ESLint 違反の修正を試みるプロンプトを作成します。

You are an AI assistant who specializes in resolving lint violations in projects. Use the tools available to quickly take action and be very brief.
1. Run linter.
2. Evaluate total violations.
 // What to do?

残念ながら、ESLintツールからのlint違反について学習する際には、障害にぶつかっています。 サマリー出力を使用する場合、修正している内容を把握するのに十分な情報がありません。 ただし、JSON出力を使用すると、プロジェクト内の違反が 100 件程度であるため、ESLintが標準出力に対して 10、000 文字以上を送信することがわかりました。 現在の多くのモデルでは、 4-8kトークンに制限されているため、これは問題になります。 この大きな出力を、トークンを消費しずに保持する方法が必要です。

成果 物

ESLintを使用したいのですが、モデルのコンテキストサイズを超えてAIの会話を簡単に膨らませることができます。 これに対処するために、ESLint ツールを変更して、新しいエフェメラル Docker ボリュームにeslint.jsonを書き込むようにしました。 このボリュームの読み取りと書き込みは、ツール間の別の会話として機能しますが、LLM の状況依存の関数呼び出し出力からはサンドボックス化されます。 

要約された違反の数に応じて、さまざまな方法で ESLint アーティファクトを使用するツールを追加しました。

- name: parse_lint_results
  description: Loads lint violations grouped by type.
  parameters:
    type: object
      properties:
        outputLevel:
   	  type: string
   	  description: Supports condensed or complaints
  container:
    image: vonwig/read_eslint

これで、このツールを使用してプロンプトを終了できます。

You are an AI assistant who specializes in resolving lint violations in projects. Use the tools available to quickly take action and be very brief.
1. Run lint. // Will write /thread/eslint.json
2. Evaluate total violations. // Will read /thread/eslint.json
<10 violations: Parse output with complaints output.
10+ violations: Parse output with condensed output.
3. Fix the violations using the following steps:
## Condensed:
{>fixing}

次のユーザープロンプト:

1. Get the line Use read_eslint with the `path` arg to get all of the violations for a file.
2. Make the correction Respond in the following format:

```json
{
"start": [1, 4],
"end": [2, 4],
"edit": "Lorem ipsum"
}
```

Once you have fixed one file, move on to the next.
You are able to fix the following violations:
no-async-promise-executor
... 

利回り:

The violation is located in the file src/utils/promiseUtils.ts at line 30-31. The current code is:
```javascript
return new Promise(async (resolve, reject) => {
  ...
});
```

To resolve the no-async-promise-executor violation, remove the async keyword from the `Promise` executor function. The corrected code would look like:

```javascript
return new Promise((resolve, reject) => {
  ...
});
```

残念ながら、まだ良い結果が出ていません。 コードからの違反コンテキストがなければ、繰り返しになりますが、アシスタントは実行可能な修正を提供できません。 ですから、それを実現するためのツールを作る必要があります。

ツリーシッター

適切なツールがなければ、LLMは、せいぜい曖昧で役に立ち、最悪の場合、幻覚を見やすくなっています。 ここでは、LLMを実行可能にするためのツールが必要です。 Tree-sitter は、さまざまな言語を抽象構文ツリー (AST) に解析するために使用できる人気のあるオープンソース ツールです。 

私たちが利用したいツリーシッターの強力な部分は、アシスタントが遭遇する可能性のあるほとんどすべての言語をサポートする文法著者のコミュニティです。 このツールは、ファイルパスと行番号が与えられたコンテキストを取得するためにDocker化しました。

業績

ペイロードからのデバッグ終了応答をトリミングしましたが、関数呼び出しは保持しました。

## ROLE assistant
...({:function {:name run_lint, :arguments {}}, :id call_MaK7CGpOISktz1fZP3GS7m4H})

## ROLE assistant
.........................({:function {:name run-eslint, :arguments {
  "args": ".",
"version": 8,
"outputLevel": "summary"
}}, :id call_RHX2hztWvghxbyZx5cvSXgMU})

## ROLE tool (run-eslint)
Running npx with args: eslint@8 --format json .
Peparing output
Found 41 violations in 271 files.

## ROLE tool (run_lint)
I ran ESLint (version 8) on your entire project. Here are the results:

- 271 files were checked for violations
- Out of these, 41 files had one or more violations

## ROLE assistant
.............({:function {:name parse_lint_results, :arguments {
  "outputLevel": "condensed"
}}, :id call_sYHP8tXuKbXGaXdNCdO3W5kU})

## ROLE tool (parse_lint_results)
{   "@typescript-eslint/no-floating-promises": [ "src/commands/help.ts",
"src/commands/registerWorkspaceCommand.ts"   ],   "@typescript-eslint/no-explicit-any": [ "src/commands/registerLocalCommand.ts"   ],   "@typescript-eslint/naming-convention": [ "src/constants.ts"   ],   "eqeqeq": [ "src/debugging/DockerDebugConfigurationProvider.ts", "src/debugging/DockerServerReadyAction.ts", "src/runtimes/files/ContainerFilesProvider.ts", "src/tree/LocalRootTreeItemBase.ts"   ],   "@typescript-eslint/no-unused-vars": [ "src/extension.ts", "src/scaffolding/wizard/netCore/NetCoreGatherInformationStep.ts"   ],   "@typescript-eslint/semi": [ "src/utils/registryExperience.ts"   ] }

## ROLE assistant
...............({:function {:name violations_for_file, :arguments {
  "path": "src/commands/help.ts"
}}, :id call_fAN5kTrXndaNs7Ix4iH51E4T})

## ROLE tool (violations_for_file)
Getting eslint.json for path: src/commands/help.ts
ESLint violations for src/commands/help.ts:
{ "filePath": "src/commands/help.ts", "messages": [ { "ruleId": "@typescript-eslint/no-floating-promises", "severity": 1, "message": "Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the void operator.", "line": 35, "column": 5, "nodeType": "ExpressionStatement", "messageId": "floatingVoid", "endLine": 35, "endColumn": 100] }

## ROLE assistant
......................({:function {:name run_tree_sitter, :arguments {
  "path": "src/commands/help.ts",
  "line": 35
}}, :id call_cKnNRQs5hmMsTszTfDnwfK12})

## ROLE tool (run_tree_sitter)
{
  offending_line: '}',
  line_node: SyntaxNode {
type: },
startPosition: {row: 35, column: 0},
endPosition: {row: 35, column: 1},
childCount: 0,
  },
  parent: SetNode {
type: set,
startPosition: {row: 33, column: 45},
endPosition: {row: 35, column: 1},
childCount: 4,
  },
  parent_text: '{\n' +
" vscode.env.openExternal(vscode.Uri.parse('https://github.com/microsoft/vscode-docker/issues'));\n" +
'}'
}

## ROLE assistant
The violation on line 35 of the `src/commands/help.ts` file is due to a floating promise. To resolve this, add the void operator to the beginning of the line as below:
```js
void vscode.env.openExternal(vscode.Uri.parse('https://github.com/microsoft/vscode-docker/issues'));
```.

この結果は、LLM が適切なツールを使用して小さなコード改善を調整できることを示しています。

障害

残念ながら、次の違反に進むのではなく、最初の違反が終了すると終了します。 これを変更するのは難しそうで、他の 2 つのプロンプトの組み合わせを試してもループを進行させることができませんでした。

Fix any lint violations you can using the tools provided.
After resolving one violation, move onto the next.
Once you have fixed one file, move on to the next.

成功したプロンプト

しかし、私たちが見つけたのは、焦点を当てるべき糸くずの破れを特定することがうまくいったということです。

Please only fix no-unused-vars

利回り:

## ROLE assistant
The violation in the file "src/extension.ts" is a declared variable 'unuseVar' at line 41, which is not used anywhere. The fix would be the removal of that line..nil

図 3 は、テストしたいくつかの興味深い違反を示しています。

テストされた違反の結果を示すテーブルと、違反、結果、フィードバックの列を示すスクリーンショット。
図 3: テストされた違反。

全体として、私たちのアシスタントは、違反を見つけて修正するための適切なツールを与えられれば、困難な糸くず違反に対しても適切なコード変更の提案を行うことができることがわかります。 コードを確認し、カバーしていないさまざまな違反でテストすることをお勧めします。

概要

私たちは、コンテキストを収集し、提案を改善するためのツールの使用を引き続き調査しています。 今回は、AIアシスタントが開発者に大きな価値を提供する方法を見てきました。

  • リンターを使用して、Node、NPM、または ESLint を使用しない TS プロジェクトの違反について学習します。
  • エフェメラルボリュームを活用して、トークンを使用せずに大きなコンテキストを保存します。
  • Tree_sitterを使用して、プロジェクトから正確で関連性の高いコード コンテキストを読み込みます。
  • TS プロジェクトでの違反に対する修正の生成。

いつものように、新しい 公開リポジトリ でお気軽にフォローしてください。 このブログ記事で説明した内容はすべて、自分のプロジェクトで試すことができます。

さらに詳しく