Gemini CLI カスタムツール サンプルスクリプト (改訂版)

このファイルは、Gemini CLIのカスタムツールを作成する際のテンプレートです。
これまでの知見(`__main__`ブロックの禁止、`stdin`経由の引数受け渡し、依存関係の処理など)を全て反映しています。


#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
A sample script for a Gemini CLI custom tool.

This script serves as a template and demonstrates the best practices we've
established. It is designed to be called by the 'call_tool' dispatcher,
receiving its arguments via a JSON object on stdin.
"""

import sys
import json
import logging
from typing import List # 必要に応じて型ヒントをインポート

# --- 1. 依存関係のハンドリング (Dependency Handling) ---
# 外部ライブラリをインポートする場合、必ず try...except ImportError ブロックで囲む。
# これにより、ライブラリがインストールされていない場合に、ユーザーに親切な
# エラーメッセージとインストール方法を提示できる。
try:
    import requests # 例としてrequestsライブラリを使用
except ImportError:
    # ログ(stderr)にエラーメッセージとインストール手順を出力して終了する
    logging.error(
        "ERROR: The 'requests' library is not installed. "
        "Please install it by running: pip install requests"
    )
    sys.exit(1)


# --- 2. 基本設定 (Basic Configuration) ---
# 全てのログは、Gemini CLIがユーザーに表示する `returnDisplay` の元となる
# 標準エラー出力(stderr)に書き出すように設定する。
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - [%(levelname)s] - %(message)s',
    stream=sys.stderr,
)


# --- 3. main関数: 唯一のインターフェース ---
# ツールのインターフェース(引数)は、このmain関数のシグネチャによってのみ定義される。
# これが、Gemini CLIがget_tools.pyを生成する際の唯一の「真実の源」となる。
#
# - 必須引数: デフォルト値なしで定義する (例: name: str)
# - 任意引数: 必ずデフォルト値を与える (例: repeat: int = 1)
def main(name: str, repeat: int = 1, loud: bool = False):
    """
    A sample tool that generates a greeting string.

    This docstring is important. Gemini CLI will use it as a reference
    to generate the 'description' for this tool in get_tools.py.

    Args:
        name (str): The name to include in the greeting. This is a required argument.
        repeat (int, optional): The number of times to repeat the greeting. Defaults to 1.
        loud (bool, optional): If True, the greeting will be in uppercase. Defaults to False.
    """
    # 処理開始と受け取った引数をログに出力する(デバッグに有用)
    logging.info(f"Tool 'sample_tool' started with args: name='{name}', repeat={repeat}, loud={loud}")

    try:
        # --- 4. 主要ロジック (Core Logic) ---
        # ここにツールの主となる処理を記述する。

        # 例: あいさつ文を生成
        greeting = f"Hello, {name}!"
        if loud:
            greeting = greeting.upper()
        
        # 複数行の文字列を生成
        final_output = "\n".join([greeting] * repeat)

        # --- 5. 成功時の出力 (Success Output) ---
        # 処理が成功した場合、LLMに渡したい結果の「文字列のみ」を標準出力(stdout)にprintする。
        # これが `llmContent` となる。
        print(final_output)

    except Exception as e:
        # --- 6. エラーハンドリング (Error Handling) ---
        # 予期せぬエラーが発生した場合、詳細を標準エラー出力(stderr)にログとして書き出し、
        # ゼロ以外のステータスコードで終了する。
        logging.error(f"An unexpected error occurred: {e}")
        sys.exit(1)


# --- 7. 禁止事項: if __name__ == "__main__" ---
#
# 以下のブロックは、仕様の二重管理(main関数のシグネチャ vs argparse)という
# 深刻な矛盾とバグの原因となるため、**絶対に記述してはならない。**
#
# if __name__ == '__main__':
#     # このブロックは禁止!
#     pass