Open19

Googleのコーディングエージェント「Jules」を使ってみる

Yuma ItoYuma Ito

Julesとは

https://jules.google/docs

Jules is an experimental coding agent that helps you fix bugs, add documentation, and build new features. It integrates with GitHub, understands your codebase, and works asynchronously — so you can move on while it handles the task.

Googleによって発表されたコーディングエージェントのこと。
https://www.publickey1.jp/blog/24/_aijulesgoogle.html

Yuma ItoYuma Ito

依頼したタスク

TypeScriptの型チェックをするGitHub Actionsワークフローの実装をしてもらいました。
実装の過程はこのスクラップにメモしています。

最終的なコードのプルリクエストは以下です。
https://github.com/yuma-ito-bd/schedule-line-reminder/pull/48

触ってみた感想

  • かなりざっくりとした要求をしてしまったためか、何回もやりとりを往復する必要があった。
    • 実行計画をよく確認して、ヌケモレがないかチェックした方が良さそう。
  • 仮想マシン内でコマンドを実行してくれてコードを修正してくれるのはありがたい。
    • ただし、Node.jsの実行環境は古かった (v18.19.1)が、今後の更新に期待
  • 日本語ユーザーはIMEの変換でエンターキーを押すとメッセージが送信されてしまうので、エディタでプロンプトを作ってからコピペした方がよい。
Yuma ItoYuma Ito

TypeScriptの型チェックを行うGitHub Actionsワークフローを作ってもらう

最初のタスクは TypeScriptのコードの型チェックを行うGitHub Actionsワークフローを作ってもらうことにした。

最初のプロンプトは以下。(かなりざっくりしてしまった)

Bunでは型チェックをすることができないため、別途型チェックできるようにする。
GitHub Actionsのワークフローを導入する。
Yuma ItoYuma Ito

実行計画の承認

しばらくすると(1分以内)、Julesが何をするか記載した実行計画が出力された。

これで問題なければApproveする。

Yuma ItoYuma Ito

1分ほどでコードが出力された

簡単なタスクだったためか、1分でコードが出力された。

以下のようなGitHub Actionsワークフローの設定ファイルであった。

name: Type Check

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  type-check:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20' # Or your project's Node.js version

      - name: Set up Bun
        uses: oven-sh/setup-bun@v1
        with:
          bun-version: 'latest' # Or your project's Bun version

      - name: Install dependencies
        run: bun install

      - name: Run type checker
        run: bun typecheck # Or your project's specific type check command

画面はこんな感じ。

Yuma ItoYuma Ito

日本語の変換を確定させようとエンターキーを押したら送信されてしまった

Node.js環境での検証は不要。

と入力しようとしたら、変換を確定させるときのエンターキーによってコメントが途中で送信されてしまった。

今後、解消されることを期待したい。

右上にある「Feedback」ボタンからフィードバックしておいた。

Yuma ItoYuma Ito

修正1:コマンドを実行できるようにする

仕方がないので別の場所で以下の文章を打ってからコピペした。

Node.js環境での検証は不要。
`bun typecheck`を実行するときのコマンドを`package.json`に追加して。
型チェックで必要なパッケージも追加して。

すると4分で出力された。

Node.js環境のセットアップが削除された。

.github/workflows/type-check.yml
name: Type Check

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  type-check:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

-     - name: Set up Node.js
-       uses: actions/setup-node@v4
-       with:
-         node-version: '20' # Or your project's Node.js version

      - name: Set up Bun
        uses: oven-sh/setup-bun@v1
        with:
          bun-version: 'latest' # Or your project's Bun version

      - name: Install dependencies
        run: bun install

      - name: Run type checker
        run: bun typecheck # Or your project's specific type check command
package.json
{
  "name": "schedule-line-reminder",
  "version": "0.0.1",
  "module": "index.ts",
  "scripts": {
    "build": "sam build",
    "deploy": "sam deploy --profile private-admin",
    "build_and_deploy": "bun run build && bun run deploy",
    "test": "bun test __tests__ --coverage",
    "generate-line-token": "bun run scripts/make_token.js",
+   "typecheck": "bun typecheck"
  },
  "devDependencies": {
    "@types/aws-lambda": "^8.10.149",
    "@types/bun": "latest",
    "aws-sdk-client-mock": "^4.1.0",
    "esbuild": "^0.25.5",
+   "typescript": "^5.0.0"
  },
  "peerDependencies": {
    "typescript": "^5.0.0"
  },
  "type": "module",
  "dependencies": {
    "@aws-sdk/client-dynamodb": "^3.817.0",
    "@aws-sdk/util-dynamodb": "^3.817.0",
    "@googleapis/calendar": "^9.8.0",
    "@line/bot-sdk": "^9.5.1",
    "jose": "^5.9.6"
  }
}
Yuma ItoYuma Ito

修正2:型チェックのコマンドを修正

👨‍💻 「bun typecheckでは型チェックはできません。 型チェックを行う実際のコマンドをpackage.jsonに記載して。」
🤖 「I apologize for the misunderstanding. Could you please provide the actual command that should be used for type checking in your project? Once I have the correct command, I will update package.json and the GitHub workflow accordingly.
(プロジェクトでのタイプチェックに使うべき正しいコマンドを教えていただくために、誤解をお詫びいたします。正しいコマンドが分かり次第、package.json と GitHub のワークフローを更新いたします。)」

BunのドキュメントのURLを渡したらどうなるか気になったので渡してみた。
👨‍💻 「下記のURLを参考にしてコマンドを決めてください。 https://bun.sh/docs/runtime/typescript」

すると、URL先のドキュメントを読み込んだらしく、記載されている tscによる型チェックを実装してくれました。

package.json
{
  "name": "schedule-line-reminder",
  "version": "0.0.1",
  "module": "index.ts",
  "scripts": {
    "build": "sam build",
    "deploy": "sam deploy --profile private-admin",
    "build_and_deploy": "bun run build && bun run deploy",
    "test": "bun test __tests__ --coverage",
    "generate-line-token": "bun run scripts/make_token.js",
-   "typecheck": "bun typecheck"
+   "typecheck": "tsc --noEmit -p tsconfig.json"
  },
  "devDependencies": {
    "@types/aws-lambda": "^8.10.149",
    "@types/bun": "latest",
    "aws-sdk-client-mock": "^4.1.0",
    "esbuild": "^0.25.5",
    "typescript": "^5.0.0"
  },
  "peerDependencies": {
    "typescript": "^5.0.0"
  },
  "type": "module",
  "dependencies": {
    "@aws-sdk/client-dynamodb": "^3.817.0",
    "@aws-sdk/util-dynamodb": "^3.817.0",
    "@googleapis/calendar": "^9.8.0",
    "@line/bot-sdk": "^9.5.1",
    "jose": "^5.9.6"
  }
}
Yuma ItoYuma Ito

修正3:GitHub ActionsワークフローでのBunのバージョンを指定

GitHub Actionsのワークフローでは.tool-versionsに記載されているBunのバージョンで動かしてほしかったので、下記のようにコメントした。

👨‍💻 「GitHub Actionsのワークフローにおいて、Bunのバージョンは.tool-versionsファイルから読み取るようにして」

今度は8分ほどで修正してくれました。

.github/workflows/type-check.yml
name: Type Check

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  type-check:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Bun
-      uses: oven-sh/setup-bun@v1
+      uses: oven-sh/setup-bun@v2
        with:
-        bun-version: 'latest' # Or your project's Bun version
+        bun-version-file: '.tool-versions'

      - name: Install dependencies
        run: bun install

      - name: Run type checker
        run: bun run typecheck # Or your project's specific type check command
Yuma ItoYuma Ito

修正4:ワークフローの実行にブランチ名の条件を削除

👨‍💻 「このワークフローはすべてのプルリクエストとプッシュで実行して。ブランチ名でのフィルタリングは不要。」

と指示すると、以下のようにコードが出力された。

.github/workflows/type-check.yml
name: Type Check

- on:
-   push:
-    branches: [ main ]
-  pull_request:
-    branches: [ main ]
+ on: [push, pull_request]

(略)
Yuma ItoYuma Ito

PR作成

おそらく作業が一通り完了したので、「Publish Branch」する。

コマンドを実行する環境がないので、はたして動くだろうか。。。

Julesがやってくれるのはブランチのプッシュまで。

ここまでのコードの差分は以下。
https://github.com/yuma-ito-bd/schedule-line-reminder/compare/b94bf6ae02f72e42ee89d63186e2e829ac8716c6...11276f4f8e8be22ecbd3101da0252cb46bce3231

プルリクエストは自分で作成する。

作成したプルリクエストはこちら。
https://github.com/yuma-ito-bd/schedule-line-reminder/pull/48

Yuma ItoYuma Ito

型チェックの実行

ドキュメントを見落としてしまっていたのだが、Julesは仮想マシンの中でテストを実行できるとのこと。

Jules runs each task inside a secure, short-lived virtual machine (VM). This lets it clone your repository, install dependencies, and run tests.
To make sure Jules can do its job effectively, you can provide setup scripts that prepare the environment.

https://jules.google/docs/environment/

そこで、型チェックを実行して修正してもらうことにした。

👨‍💻 「型チェックを実行して、エラーが出たら修正して。」

すると、型チェックを実行してチェックが通るところまで修正してくれました!
ざっくり以下の内容でした。

  • 新しく追加したnpmスクリプト(typecheck)ではなくnpx tsc --noEmit -p tsconfig.jsonを実行
  • @types/jest を依存関係に追加
  • 型エラーが起きていた箇所を修正
    - global.fetch = fetchMock;
    + global.fetch = fetchMock as unknown as typeof fetch;
    

ちなみに、途中のログに出力されたのですが、Node.js 18.19.1 の環境で動いていました 😮

node -v && npm -v
v18.19.1
9.2.0
Yuma ItoYuma Ito

Cursorの場合

Cursorで同じプロンプトを投げてみたら、GitHub Actionsのワークフローファイルはあまり変わらなかったが、Prettierによるフォーマットも導入されてしまった。

Bunでは型チェックをすることができないため、別途型チェックできるようにする。
GitHub Actionsのワークフローを導入する。
.github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  type-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"

      - name: Install dependencies
        run: npm install

      - name: Type check
        run: npx tsc --noEmit

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Bun
        uses: oven-sh/setup-bun@v1
        with:
          bun-version: latest

      - name: Install dependencies
        run: bun install

      - name: Run tests
        run: bun test

  format:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Bun
        uses: oven-sh/setup-bun@v1
        with:
          bun-version: latest

      - name: Install dependencies
        run: bun install

      - name: Check formatting
        run: bun run format:check

コミットは以下。
https://github.com/yuma-ito-bd/schedule-line-reminder/pull/49/commits/58a59eb32071f67714c93b6b46ef539d84cb06a0

Yuma ItoYuma Ito

実験2:LINEのWebhookメッセージの署名を検証する

今回取り組むお題はこちら。

https://github.com/yuma-ito-bd/schedule-line-reminder/issues/26

Yuma ItoYuma Ito

プロンプトをGeminiに生成してもらう

前回はプロンプトが大雑把すぎたので今度はもう少し丁寧に指示することにした。
まずはJulesに指示したい内容を整理する。

・LINEのWebhookの署名を検証する処理を追加する。
・署名は`x-line-signature`というリクエストヘッダである。
・署名検証の内容は以下のURLに詳しく書いてあるので参照してほしい。
https://developers.line.biz/en/docs/messaging-api/receiving-messages/
・LINE SDKを利用しているので、署名検証用の関数があるはず。
https://github.com/line/line-bot-sdk-nodejs
・リポジトリの説明は以下のファイルで説明している。
.cursor/rules/schedule-line-reminder-rule.mdc

次にGeminiでより良いプロンプトに変換してもらう。

GoogleのAIコーディングエージェントであるJulesに開発タスクを依頼します。以下の内容をJulesに分かりやすい形で整形して。

[上記のプロンプト]

すると以下のようなプロンプトが生成された。

## Julesへの開発タスク依頼

### タスク概要
LINEのWebhookで受信するリクエストの署名検証処理を追加してください。

### 詳細

1.  **署名ヘッダ**: 署名はHTTPリクエストヘッダの`x-line-signature`に格納されています。

2.  **署名検証の詳細**: 署名検証の具体的なロジックについては、以下のLINE Developersドキュメントを参照してください。
    * https://developers.line.biz/en/docs/messaging-api/receiving-messages/

3.  **使用SDK**: LINE Bot SDK for Node.jsを利用しています。このSDKには署名検証のためのヘルパー関数が提供されているはずですので、そちらを利用してください。
    * GitHubリポジトリ: https://github.com/line/line-bot-sdk-nodejs

4.  **関連ファイル**: 現在のリポジトリの構造とルールについては、以下のファイルに説明がありますので、必要に応じて参照してください。
    * .cursor/rules/schedule-line-reminder-rule.mdc

### 期待される成果
LINEのWebhookが`x-line-signature`ヘッダを検証し、不正なリクエストを拒否できるようになること。
Yuma ItoYuma Ito

実験3:アクセストークン・リフレッシュトークンを自動で更新する

https://github.com/yuma-ito-bd/schedule-line-reminder/issues/36

Yuma ItoYuma Ito

プロンプトの変換

以下の内容をプロンプトに変換して。

・Googleのアクセストークンやリフレッシュトークンの変更を検知して、更新する改修を行う。
・そうしないと期限切れになってしまうため。
・以下のように `tokens`イベントによって変更を検知できる。
```js
oauth2Client.on('tokens', (tokens) => {
  if (tokens.refresh_token) {
    // store the refresh_token in my database!
    console.log(tokens.refresh_token);
  }
  console.log(tokens.access_token);
});
\```
参考:https://github.com/googleapis/google-api-nodejs-client?tab=readme-ov-file#handling-refresh-tokens

・トークンは`TokenRepository`によって管理している。updateTokenメソッドによって更新できる。
・プロジェクト全体のルールは以下のファイルで説明している。
.cursor/rules/schedule-line-reminder-rule.mdc

## Googleアクセストークン/リフレッシュトークン更新機能の追加

### 目的
Googleのアクセストークンおよびリフレッシュトークンが期限切れになることを防ぐため、これらのトークンの変更を検知し、自動的に更新する機能を追加します。

### 詳細

1.  **トークン変更の検知**:
    Google APIの`oauth2Client`インスタンスは、トークンが更新された際に`tokens`イベントを発行します。このイベントをリッスンすることで、新しいアクセストークンやリフレッシュトークンを取得できます。
    参考: [https://github.com/googleapis/google-api-nodejs-client?tab=readme-ov-file#handling-refresh-tokens](https://github.com/googleapis/google-api-nodejs-client?tab=readme-ov-file#handling-refresh-tokens)

    **イベントリスナーの例**:
    ```javascript
    oauth2Client.on('tokens', (tokens) => {
      if (tokens.refresh_token) {
        // store the refresh_token in my database!
        console.log(tokens.refresh_token);
      }
      console.log(tokens.access_token);
    });
    ```

2.  **トークンの更新**:
    取得した新しいアクセストークンとリフレッシュトークンは、既存の`TokenRepository`クラスの`updateToken`メソッドを使用してデータベースに保存し、更新してください。

### 関連ファイル

プロジェクト全体のルールや構成については、以下のファイルを参照してください。
* `.cursor/rules/schedule-line-reminder-rule.mdc`