{"meta":{"title":"初めてのCopilot搭載アプリを構築する","intro":"このチュートリアルでは、Copilot SDK を使用してコマンド ライン アシスタントを構築します。 基本から始めて、ストリーミング応答を追加し、その後カスタム ツールを追加して、Copilot にコードを呼び出す機能を与えます。","product":"GitHub Copilot","breadcrumbs":[{"href":"/ja/copilot","title":"GitHub Copilot"},{"href":"/ja/copilot/how-tos","title":"方法"},{"href":"/ja/copilot/how-tos/copilot-sdk","title":"Copilot SDK"},{"href":"/ja/copilot/how-tos/copilot-sdk/getting-started","title":"はじめに"}],"documentType":"article"},"body":"# 初めてのCopilot搭載アプリを構築する\n\nこのチュートリアルでは、Copilot SDK を使用してコマンド ライン アシスタントを構築します。 基本から始めて、ストリーミング応答を追加し、その後カスタム ツールを追加して、Copilot にコードを呼び出す機能を与えます。\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n**ビルドする内容:**\n\n```text\nYou: What's the weather like in Seattle?\nCopilot: Let me check the weather for Seattle...\n         Currently 62°F and cloudy with a chance of rain.\n         Typical Seattle weather!\n\nYou: How about Tokyo?\nCopilot: In Tokyo it's 75°F and sunny. Great day to be outside!\n```\n\n## Prerequisites\n\n開始する前に、以下の項目があることを確認します:\n\n* **GitHub Copilot CLI** がインストールされ、認証されていること（Node.js、Python、.NET SDK では CLI が自動的に提供されます。[既定のセットアップ (バンドルされた CLI)](/ja/copilot/how-tos/copilot-sdk/setup/bundled-cli) を参照してください）。 Go、Java、Rust に必要です (アプリケーション レベルの CLI バンドル機能を使用しない場合)。\n* お好みの言語ランタイム:\n  * **Node.js** 20+ または **Python** 3.11 以降または **Go** 1.24 以上または> **Rust** 1.94 以上または **Java** 17 以上または **.NET** 8.0 以降\n\nCLI が動作していることを確認します。\n\n```bash\ncopilot --version\n```\n\n## 手順 1: SDK をインストールする\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\nまず、新しいディレクトリを作成し、プロジェクトを初期化します。\n\n```bash\nmkdir copilot-demo && cd copilot-demo\nnpm init -y --init-type module\n```\n\n次に、SDK と TypeScript ランナーをインストールします。\n\n```bash\nnpm install @github/copilot-sdk tsx\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```bash\npip install github-copilot-sdk\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\nまず、新しいディレクトリを作成し、モジュールを初期化します。\n\n```bash\nmkdir copilot-demo && cd copilot-demo\ngo mod init copilot-demo\n```\n\n次に、SDK をインストールします。\n\n```bash\ngo get github.com/github/copilot-sdk/go\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\nまず、新しいバイナリ クレートを作成します。\n\n```bash\ncargo new copilot-demo && cd copilot-demo\n```\n\n次に、例で使用される SDK と直接の依存関係をインストールします。\n\n```bash\ncargo add github-copilot-sdk --features derive\n# Used by #[tokio::main] and tokio::spawn\ncargo add tokio --features rt-multi-thread,macros\n# Used by custom-tool parameter derives later in this guide\ncargo add serde --features derive\ncargo add schemars\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\nまず、新しいコンソール プロジェクトを作成します。\n\n```bash\ndotnet new console -n CopilotDemo && cd CopilotDemo\n```\n\n次に、SDK を追加します。\n\n```bash\ndotnet add package GitHub.Copilot.SDK\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\nまず、新しいディレクトリを作成し、プロジェクトを初期化します。\n\n**Maven** — `pom.xml`に追加します。\n\n```xml\n<dependency>\n    <groupId>com.github</groupId>\n    <artifactId>copilot-sdk-java</artifactId>\n    <version>${copilot.sdk.version}</version>\n</dependency>\n```\n\n**Gradle** — `build.gradle`に追加します。\n\n```groovy\nimplementation 'com.github:copilot-sdk-java:${copilotSdkVersion}'\n```\n\n</div>\n\n</div>\n\n## 手順 2: 最初のメッセージを送信する\n\n新しいファイルを作成し、次のコードを追加します。 これは、SDK (約 5 行のコード) を使用する最も簡単な方法です。\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n`index.ts`を作成します。\n\n```typescript\nimport { CopilotClient } from \"@github/copilot-sdk\";\n\nconst client = new CopilotClient();\nconst session = await client.createSession({ model: \"auto\" });\n\nconst response = await session.sendAndWait({ prompt: \"What is 2 + 2?\" });\nconsole.log(response?.data.content);\n\nawait client.stop();\nprocess.exit(0);\n```\n\n次のコマンドを実行します。\n\n```bash\nnpx tsx index.ts\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n`main.py`を作成します。\n\n```python\nimport asyncio\nfrom copilot import CopilotClient\nfrom copilot.session import PermissionHandler\n\nasync def main():\n    client = CopilotClient()\n    await client.start()\n\n    session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model=\"auto\")\n    response = await session.send_and_wait(\"What is 2 + 2?\")\n    print(response.data.content)\n\n    await client.stop()\n\nasyncio.run(main())\n```\n\n次のコマンドを実行します。\n\n```bash\npython main.py\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n`main.go`を作成します。\n\n```golang\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n    \"os\"\n\n    copilot \"github.com/github/copilot-sdk/go\"\n)\n\nfunc main() {\n    ctx := context.Background()\n    client := copilot.NewClient(nil)\n    if err := client.Start(ctx); err != nil {\n        log.Fatal(err)\n    }\n    defer client.Stop()\n\n    session, err := client.CreateSession(ctx, &copilot.SessionConfig{Model: \"auto\"})\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    response, err := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: \"What is 2 + 2?\"})\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    if d, ok := response.Data.(*copilot.AssistantMessageData); ok {\n        fmt.Println(d.Content)\n    }\n    os.Exit(0)\n}\n```\n\n次のコマンドを実行します。\n\n```bash\ngo run main.go\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\n`src/main.rs`を作成します。\n\n```rust\nuse std::sync::Arc;\nuse std::time::Duration;\n\nuse github_copilot_sdk::handler::ApproveAllHandler;\nuse github_copilot_sdk::{Client, ClientOptions, MessageOptions, SessionConfig};\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let client = Client::start(ClientOptions::default()).await?;\n    let session = client\n        .create_session(SessionConfig::default().with_permission_handler(Arc::new(ApproveAllHandler)))\n        .await?;\n\n    let response = session\n        .send_and_wait(\n            MessageOptions::new(\"What is 2 + 2?\").with_wait_timeout(Duration::from_secs(120)),\n        )\n        .await?;\n\n    if let Some(event) = response {\n        if let Some(content) = event.data.get(\"content\").and_then(|value| value.as_str()) {\n            println!(\"{content}\");\n        }\n    }\n\n    session.disconnect().await?;\n    client.stop().await?;\n    Ok(())\n}\n```\n\n次のコマンドを実行します。\n\n```bash\ncargo run\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n新しいコンソール プロジェクトを作成し、これを `Program.cs`に追加します。\n\n```csharp\nusing GitHub.Copilot;\n\nawait using var client = new CopilotClient();\nawait using var session = await client.CreateSessionAsync(new SessionConfig\n{\n    Model = \"auto\",\n    OnPermissionRequest = PermissionHandler.ApproveAll\n});\n\nvar response = await session.SendAndWaitAsync(new MessageOptions { Prompt = \"What is 2 + 2?\" });\nConsole.WriteLine(response?.Data.Content);\n```\n\n次のコマンドを実行します。\n\n```bash\ndotnet run\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n`HelloCopilot.java`を作成します。\n\n<!-- docs-validate: skip -->\n\n```java\nimport com.github.copilot.CopilotClient;\nimport com.github.copilot.rpc.*;\n\npublic class HelloCopilot {\n    public static void main(String[] args) throws Exception {\n        try (var client = new CopilotClient()) {\n            client.start().get();\n\n            var session = client.createSession(\n                new SessionConfig()\n                    .setModel(\"auto\")\n                    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)\n            ).get();\n\n            var response = session.sendAndWait(\n                new MessageOptions().setPrompt(\"What is 2 + 2?\")\n            ).get();\n\n            System.out.println(response.getData().content());\n\n            client.stop().get();\n        }\n    }\n}\n```\n\n次のコマンドを実行します。\n\n```bash\njavac -cp copilot-sdk.jar HelloCopilot.java && java -cp .:copilot-sdk.jar HelloCopilot\n```\n\n</div>\n\n</div>\n\n**次のように表示されます:**\n\n```text\n4\n```\n\nおめでとうございます! Copilot を活用したアプリを初めて構築しました。\n\n## 手順 3: ストリーミング応答を追加する\n\n現時点では、何かを表示する前に、完全な応答を待ちます。 生成された応答をストリーミングして対話型にしましょう。\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n`index.ts`を更新してください。\n\n```typescript\nimport { CopilotClient } from \"@github/copilot-sdk\";\n\nconst client = new CopilotClient();\nconst session = await client.createSession({\n    model: \"auto\",\n    streaming: true,\n});\n\n// Listen for response chunks\nsession.on(\"assistant.message_delta\", (event) => {\n    process.stdout.write(event.data.deltaContent);\n});\nsession.on(\"session.idle\", () => {\n    console.log(); // New line when done\n});\n\nawait session.sendAndWait({ prompt: \"Tell me a short joke\" });\n\nawait client.stop();\nprocess.exit(0);\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n`main.py`を更新してください。\n\n```python\nimport asyncio\nimport sys\nfrom copilot import CopilotClient\nfrom copilot.session import PermissionHandler\nfrom copilot.session_events import SessionEventType\n\nasync def main():\n    client = CopilotClient()\n    await client.start()\n\n    session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model=\"auto\", streaming=True)\n\n    # Listen for response chunks\n    def handle_event(event):\n        if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:\n            sys.stdout.write(event.data.delta_content)\n            sys.stdout.flush()\n        if event.type == SessionEventType.SESSION_IDLE:\n            print()  # New line when done\n\n    session.on(handle_event)\n\n    await session.send_and_wait(\"Tell me a short joke\")\n\n    await client.stop()\n\nasyncio.run(main())\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n`main.go`を更新してください。\n\n```golang\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n    \"os\"\n\n    copilot \"github.com/github/copilot-sdk/go\"\n)\n\nfunc main() {\n    ctx := context.Background()\n    client := copilot.NewClient(nil)\n    if err := client.Start(ctx); err != nil {\n        log.Fatal(err)\n    }\n    defer client.Stop()\n\n    session, err := client.CreateSession(ctx, &copilot.SessionConfig{\n        Model:     \"auto\",\n        Streaming: copilot.Bool(true),\n    })\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    // Listen for response chunks\n    session.On(func(event copilot.SessionEvent) {\n        switch d := event.Data.(type) {\n        case *copilot.AssistantMessageDeltaData:\n            fmt.Print(d.DeltaContent)\n        case *copilot.SessionIdleData:\n            _ = d\n            fmt.Println()\n        }\n    })\n\n    _, err = session.SendAndWait(ctx, copilot.MessageOptions{Prompt: \"Tell me a short joke\"})\n    if err != nil {\n        log.Fatal(err)\n    }\n    os.Exit(0)\n}\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\n`src/main.rs`を更新してください。\n\n```rust\nuse std::io::{self, Write};\nuse std::sync::Arc;\nuse std::time::Duration;\n\nuse github_copilot_sdk::handler::ApproveAllHandler;\nuse github_copilot_sdk::{Client, ClientOptions, MessageOptions, SessionConfig};\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let client = Client::start(ClientOptions::default()).await?;\n\n    let mut config = SessionConfig::default();\n    config.streaming = Some(true);\n    let session = client\n        .create_session(config.with_permission_handler(Arc::new(ApproveAllHandler)))\n        .await?;\n\n    // Listen for response chunks\n    let mut events = session.subscribe();\n    tokio::spawn(async move {\n        while let Ok(event) = events.recv().await {\n            match event.event_type.as_str() {\n                \"assistant.message_delta\" => {\n                    if let Some(text) =\n                        event.data.get(\"deltaContent\").and_then(|value| value.as_str())\n                    {\n                        print!(\"{text}\");\n                        io::stdout().flush().ok();\n                    }\n                }\n                \"assistant.message\" => println!(),\n                _ => {}\n            }\n        }\n    });\n\n    session\n        .send_and_wait(\n            MessageOptions::new(\"Tell me a short joke\")\n                .with_wait_timeout(Duration::from_secs(120)),\n        )\n        .await?;\n\n    session.disconnect().await?;\n    client.stop().await?;\n    Ok(())\n}\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n`Program.cs`を更新してください。\n\n```csharp\nusing GitHub.Copilot;\n\nawait using var client = new CopilotClient();\nawait using var session = await client.CreateSessionAsync(new SessionConfig\n{\n    Model = \"auto\",\n    OnPermissionRequest = PermissionHandler.ApproveAll,\n    Streaming = true,\n});\n\n// Listen for response chunks\nsession.On<SessionEvent>(ev =>\n{\n    if (ev is AssistantMessageDeltaEvent deltaEvent)\n    {\n        Console.Write(deltaEvent.Data.DeltaContent);\n    }\n    if (ev is SessionIdleEvent)\n    {\n        Console.WriteLine();\n    }\n});\n\nawait session.SendAndWaitAsync(new MessageOptions { Prompt = \"Tell me a short joke\" });\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n`HelloCopilot.java`を更新してください。\n\n<!-- docs-validate: skip -->\n\n```java\nimport com.github.copilot.CopilotClient;\nimport com.github.copilot.rpc.*;\n\npublic class HelloCopilot {\n    public static void main(String[] args) throws Exception {\n        try (var client = new CopilotClient()) {\n            client.start().get();\n\n            var session = client.createSession(\n                new SessionConfig()\n                    .setModel(\"auto\")\n                    .setStreaming(true)\n                    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)\n            ).get();\n\n            // Listen for response chunks\n            session.on(AssistantMessageDeltaEvent.class, delta -> {\n                System.out.print(delta.getData().deltaContent());\n            });\n            session.on(SessionIdleEvent.class, idle -> {\n                System.out.println(); // New line when done\n            });\n\n            session.sendAndWait(\n                new MessageOptions().setPrompt(\"Tell me a short joke\")\n            ).get();\n\n            client.stop().get();\n        }\n    }\n}\n```\n\n</div>\n\n</div>\n\nコードをもう一度実行します。 応答が単語ごとに表示されます。\n\n### イベント サブスクリプションメソッド\n\nSDK には、セッション イベントをサブスクライブするためのメソッドが用意されています。\n\n| Method                   | Description                                                        |\n| ------------------------ | ------------------------------------------------------------------ |\n| `on(handler)`            | すべてのイベントをサブスクライブする。unsubscribe 関数を返します                             |\n| `on(eventType, handler)` | 特定のイベントの種類 (Node.js/TypeScript のみ) をサブスクライブします。unsubscribe 関数を返します |\n| `subscribe()`            | すべてのイベントを購読する (Rust); `event_type` で絞り込む                           |\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\n// Subscribe to all events\nconst unsubscribeAll = session.on((event) => {\n    console.log(\"Event:\", event.type);\n});\n\n// Subscribe to specific event type\nconst unsubscribeIdle = session.on(\"session.idle\", (event) => {\n    console.log(\"Session is idle\");\n});\n\n// Later, to unsubscribe:\nunsubscribeAll();\nunsubscribeIdle();\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\n# Subscribe to all events\nunsubscribe = session.on(lambda event: print(f\"Event: {event.type}\"))\n\n# Filter by event type in your handler\ndef handle_event(event):\n    if event.type == SessionEventType.SESSION_IDLE:\n        print(\"Session is idle\")\n    elif event.type == SessionEventType.ASSISTANT_MESSAGE:\n        print(f\"Message: {event.data.content}\")\n\nunsubscribe = session.on(handle_event)\n\n# Later, to unsubscribe:\nunsubscribe()\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\n// Subscribe to all events\nunsubscribe := session.On(func(event copilot.SessionEvent) {\n    fmt.Println(\"Event:\", event.Type)\n})\n\n// Filter by event type in your handler\nsession.On(func(event copilot.SessionEvent) {\n    switch d := event.Data.(type) {\n    case *copilot.SessionIdleData:\n        _ = d\n        fmt.Println(\"Session is idle\")\n    case *copilot.AssistantMessageData:\n        fmt.Println(\"Message:\", d.Content)\n    }\n})\n\n// Later, to unsubscribe:\nunsubscribe()\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\n```rust\nlet mut events = session.subscribe();\n\ntokio::spawn(async move {\n    while let Ok(event) = events.recv().await {\n        println!(\"Event: {}\", event.event_type);\n\n        match event.event_type.as_str() {\n            \"session.idle\" => println!(\"Session is idle\"),\n            \"assistant.message\" => {\n                if let Some(content) = event.data.get(\"content\").and_then(|value| value.as_str()) {\n                    println!(\"Message: {content}\");\n                }\n            }\n            _ => {}\n        }\n    }\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\n// Subscribe to all events\nvar unsubscribe = session.On<SessionEvent>(ev => Console.WriteLine($\"Event: {ev.Type}\"));\n\n// Filter by event type using pattern matching\nsession.On<SessionEvent>(ev =>\n{\n    switch (ev)\n    {\n        case SessionIdleEvent:\n            Console.WriteLine(\"Session is idle\");\n            break;\n        case AssistantMessageEvent msg:\n            Console.WriteLine($\"Message: {msg.Data.Content}\");\n            break;\n    }\n});\n\n// Later, to unsubscribe:\nunsubscribe.Dispose();\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n<!-- docs-validate: skip -->\n\n```java\n// Subscribe to all events\nvar unsubscribe = session.on(event -> {\n    System.out.println(\"Event: \" + event.getType());\n});\n\n// Subscribe to a specific event type\nsession.on(AssistantMessageEvent.class, msg -> {\n    System.out.println(\"Message: \" + msg.getData().content());\n});\n\nsession.on(SessionIdleEvent.class, idle -> {\n    System.out.println(\"Session is idle\");\n});\n\n// Later, to unsubscribe:\nunsubscribe.close();\n```\n\n</div>\n\n</div>\n\n## 手順 4: カスタム ツールを追加する\n\nでは、ここからが本題です。 Copilotカスタム ツールを定義してコードを呼び出す機能を提供しましょう。 簡単な気象検索ツールを作成します。\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n`index.ts`を更新してください。\n\n```typescript\nimport { CopilotClient, defineTool } from \"@github/copilot-sdk\";\n\n// Define a tool that Copilot can call\nconst getWeather = defineTool(\"get_weather\", {\n    description: \"Get the current weather for a city\",\n    parameters: {\n        type: \"object\",\n        properties: {\n            city: { type: \"string\", description: \"The city name\" },\n        },\n        required: [\"city\"],\n    },\n    handler: async (args: { city: string }) => {\n        const { city } = args;\n        // In a real app, you'd call a weather API here\n        const conditions = [\"sunny\", \"cloudy\", \"rainy\", \"partly cloudy\"];\n        const temp = Math.floor(Math.random() * 30) + 50;\n        const condition = conditions[Math.floor(Math.random() * conditions.length)];\n        return { city, temperature: `${temp}°F`, condition };\n    },\n});\n\nconst client = new CopilotClient();\nconst session = await client.createSession({\n    model: \"auto\",\n    streaming: true,\n    tools: [getWeather],\n});\n\nsession.on(\"assistant.message_delta\", (event) => {\n    process.stdout.write(event.data.deltaContent);\n});\n\nsession.on(\"session.idle\", () => {\n    console.log(); // New line when done\n});\n\nawait session.sendAndWait({\n    prompt: \"What's the weather like in Seattle and Tokyo?\",\n});\n\nawait client.stop();\nprocess.exit(0);\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n`main.py`を更新してください。\n\n```python\nimport asyncio\nimport random\nimport sys\nfrom copilot import CopilotClient\nfrom copilot.session import PermissionHandler\nfrom copilot.tools import define_tool\nfrom copilot.session_events import SessionEventType\nfrom pydantic import BaseModel, Field\n\n# Define the parameters for the tool using Pydantic\nclass GetWeatherParams(BaseModel):\n    city: str = Field(description=\"The name of the city to get weather for\")\n\n# Define a tool that Copilot can call\n@define_tool(description=\"Get the current weather for a city\")\nasync def get_weather(params: GetWeatherParams) -> dict:\n    city = params.city\n    # In a real app, you'd call a weather API here\n    conditions = [\"sunny\", \"cloudy\", \"rainy\", \"partly cloudy\"]\n    temp = random.randint(50, 80)\n    condition = random.choice(conditions)\n    return {\"city\": city, \"temperature\": f\"{temp}°F\", \"condition\": condition}\n\nasync def main():\n    client = CopilotClient()\n    await client.start()\n\n    session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model=\"auto\", streaming=True, tools=[get_weather])\n\n    def handle_event(event):\n        if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:\n            sys.stdout.write(event.data.delta_content)\n            sys.stdout.flush()\n        if event.type == SessionEventType.SESSION_IDLE:\n            print()\n\n    session.on(handle_event)\n\n    await session.send_and_wait(\"What's the weather like in Seattle and Tokyo?\")\n\n    await client.stop()\n\nasyncio.run(main())\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n`main.go`を更新してください。\n\n```golang\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n    \"math/rand\"\n    \"os\"\n\n    copilot \"github.com/github/copilot-sdk/go\"\n)\n\n// Define the parameter type\ntype WeatherParams struct {\n    City string `json:\"city\" jsonschema:\"The city name\"`\n}\n\n// Define the return type\ntype WeatherResult struct {\n    City        string `json:\"city\"`\n    Temperature string `json:\"temperature\"`\n    Condition   string `json:\"condition\"`\n}\n\nfunc main() {\n    ctx := context.Background()\n\n    // Define a tool that Copilot can call\n    getWeather := copilot.DefineTool(\n        \"get_weather\",\n        \"Get the current weather for a city\",\n        func(params WeatherParams, inv copilot.ToolInvocation) (WeatherResult, error) {\n            // In a real app, you'd call a weather API here\n            conditions := []string{\"sunny\", \"cloudy\", \"rainy\", \"partly cloudy\"}\n            temp := rand.Intn(30) + 50\n            condition := conditions[rand.Intn(len(conditions))]\n            return WeatherResult{\n                City:        params.City,\n                Temperature: fmt.Sprintf(\"%d°F\", temp),\n                Condition:   condition,\n            }, nil\n        },\n    )\n\n    client := copilot.NewClient(nil)\n    if err := client.Start(ctx); err != nil {\n        log.Fatal(err)\n    }\n    defer client.Stop()\n\n    session, err := client.CreateSession(ctx, &copilot.SessionConfig{\n        Model:     \"auto\",\n        Streaming: copilot.Bool(true),\n        Tools:     []copilot.Tool{getWeather},\n    })\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    session.On(func(event copilot.SessionEvent) {\n        switch d := event.Data.(type) {\n        case *copilot.AssistantMessageDeltaData:\n            fmt.Print(d.DeltaContent)\n        case *copilot.SessionIdleData:\n            _ = d\n            fmt.Println()\n        }\n    })\n\n    _, err = session.SendAndWait(ctx, copilot.MessageOptions{\n        Prompt: \"What's the weather like in Seattle and Tokyo?\",\n    })\n    if err != nil {\n        log.Fatal(err)\n    }\n    os.Exit(0)\n}\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\n`src/main.rs`を更新してください。\n\n```rust\nuse std::io::{self, Write};\nuse std::sync::Arc;\nuse std::time::Duration;\n\nuse github_copilot_sdk::handler::ApproveAllHandler;\nuse github_copilot_sdk::tool::{define_tool, JsonSchema};\nuse github_copilot_sdk::{Client, ClientOptions, MessageOptions, SessionConfig, ToolResult};\nuse serde::Deserialize;\n\n#[derive(Deserialize, JsonSchema)]\nstruct GetWeatherParams {\n    city: String,\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    // Define a tool that Copilot can call\n    let tools = vec![define_tool(\n        \"get_weather\",\n        \"Get the current weather for a city\",\n        |_inv, params: GetWeatherParams| async move {\n            Ok(ToolResult::Text(format!(\n                \"{}: 62°F and sunny\",\n                params.city\n            )))\n        },\n    )];\n\n    let client = Client::start(ClientOptions::default()).await?;\n\n    let mut config = SessionConfig::default();\n    config.streaming = Some(true);\n    let session = client\n        .create_session(\n            config\n                .with_tools(tools)\n                .with_permission_handler(Arc::new(ApproveAllHandler)),\n        )\n        .await?;\n\n    let mut events = session.subscribe();\n    tokio::spawn(async move {\n        while let Ok(event) = events.recv().await {\n            match event.event_type.as_str() {\n                \"assistant.message_delta\" => {\n                    if let Some(text) =\n                        event.data.get(\"deltaContent\").and_then(|value| value.as_str())\n                    {\n                        print!(\"{text}\");\n                        io::stdout().flush().ok();\n                    }\n                }\n                \"assistant.message\" => println!(),\n                _ => {}\n            }\n        }\n    });\n\n    session\n        .send_and_wait(\n            MessageOptions::new(\"What's the weather like in Seattle and Tokyo?\")\n                .with_wait_timeout(Duration::from_secs(120)),\n        )\n        .await?;\n\n    session.disconnect().await?;\n    client.stop().await?;\n    Ok(())\n}\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n`Program.cs`を更新してください。\n\n```csharp\nusing GitHub.Copilot;\nusing Microsoft.Extensions.AI;\nusing System.ComponentModel;\n\nawait using var client = new CopilotClient();\n\n// Define a tool that Copilot can call\nvar getWeather = CopilotTool.DefineTool(\n    ([Description(\"The city name\")] string city) =>\n    {\n        // In a real app, you'd call a weather API here\n        var conditions = new[] { \"sunny\", \"cloudy\", \"rainy\", \"partly cloudy\" };\n        var temp = Random.Shared.Next(50, 80);\n        var condition = conditions[Random.Shared.Next(conditions.Length)];\n        return new { city, temperature = $\"{temp}°F\", condition };\n    },\n    factoryOptions: new AIFunctionFactoryOptions\n    {\n        Name = \"get_weather\",\n        Description = \"Get the current weather for a city\",\n    }\n);\n\nawait using var session = await client.CreateSessionAsync(new SessionConfig\n{\n    Model = \"auto\",\n    OnPermissionRequest = PermissionHandler.ApproveAll,\n    Streaming = true,\n    Tools = [getWeather],\n});\n\nsession.On<SessionEvent>(ev =>\n{\n    if (ev is AssistantMessageDeltaEvent deltaEvent)\n    {\n        Console.Write(deltaEvent.Data.DeltaContent);\n    }\n    if (ev is SessionIdleEvent)\n    {\n        Console.WriteLine();\n    }\n});\n\nawait session.SendAndWaitAsync(new MessageOptions\n{\n    Prompt = \"What's the weather like in Seattle and Tokyo?\",\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n`HelloCopilot.java`を更新してください。\n\n<!-- docs-validate: skip -->\n\n```java\nimport com.github.copilot.CopilotClient;\nimport com.github.copilot.rpc.*;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.concurrent.CompletableFuture;\n\npublic class HelloCopilot {\n    public static void main(String[] args) throws Exception {\n        var random = new Random();\n        var conditions = List.of(\"sunny\", \"cloudy\", \"rainy\", \"partly cloudy\");\n\n        // Define a tool that Copilot can call\n        var getWeather = ToolDefinition.create(\n            \"get_weather\",\n            \"Get the current weather for a city\",\n            Map.of(\n                \"type\", \"object\",\n                \"properties\", Map.of(\n                    \"city\", Map.of(\"type\", \"string\", \"description\", \"The city name\")\n                ),\n                \"required\", List.of(\"city\")\n            ),\n            invocation -> {\n                var city = (String) invocation.getArguments().get(\"city\");\n                var temp = random.nextInt(30) + 50;\n                var condition = conditions.get(random.nextInt(conditions.size()));\n                return CompletableFuture.completedFuture(Map.of(\n                    \"city\", city,\n                    \"temperature\", temp + \"°F\",\n                    \"condition\", condition\n                ));\n            }\n        );\n\n        try (var client = new CopilotClient()) {\n            client.start().get();\n\n            var session = client.createSession(\n                new SessionConfig()\n                    .setModel(\"auto\")\n                    .setStreaming(true)\n                    .setTools(List.of(getWeather))\n                    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)\n            ).get();\n\n            session.on(AssistantMessageDeltaEvent.class, delta -> {\n                System.out.print(delta.getData().deltaContent());\n            });\n            session.on(SessionIdleEvent.class, idle -> {\n                System.out.println();\n            });\n\n            session.sendAndWait(\n                new MessageOptions().setPrompt(\"What's the weather like in Seattle and Tokyo?\")\n            ).get();\n\n            client.stop().get();\n        }\n    }\n}\n```\n\n</div>\n\n</div>\n\nそれを実行すると、Copilot がツールを呼び出して天気データを取得し、その結果を返すことがわかります。\n\n## 手順 5: 対話型アシスタントを構築する\n\nすべてを便利な対話型アシスタントにまとめてみましょう。\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\nimport { CopilotClient, defineTool } from \"@github/copilot-sdk\";\nimport * as readline from \"readline\";\n\nconst getWeather = defineTool(\"get_weather\", {\n    description: \"Get the current weather for a city\",\n    parameters: {\n        type: \"object\",\n        properties: {\n            city: { type: \"string\", description: \"The city name\" },\n        },\n        required: [\"city\"],\n    },\n    handler: async ({ city }) => {\n        const conditions = [\"sunny\", \"cloudy\", \"rainy\", \"partly cloudy\"];\n        const temp = Math.floor(Math.random() * 30) + 50;\n        const condition = conditions[Math.floor(Math.random() * conditions.length)];\n        return { city, temperature: `${temp}°F`, condition };\n    },\n});\n\nconst client = new CopilotClient();\nconst session = await client.createSession({\n    model: \"auto\",\n    streaming: true,\n    tools: [getWeather],\n});\n\nsession.on(\"assistant.message_delta\", (event) => {\n    process.stdout.write(event.data.deltaContent);\n});\n\nconst rl = readline.createInterface({\n    input: process.stdin,\n    output: process.stdout,\n});\n\nconsole.log(\"🌤️  Weather Assistant (type 'exit' to quit)\");\nconsole.log(\"   Try: 'What's the weather in Paris?'\\n\");\n\nconst prompt = () => {\n    rl.question(\"You: \", async (input) => {\n        if (input.toLowerCase() === \"exit\") {\n            await client.stop();\n            rl.close();\n            return;\n        }\n\n        process.stdout.write(\"Assistant: \");\n        await session.sendAndWait({ prompt: input });\n        console.log(\"\\n\");\n        prompt();\n    });\n};\n\nprompt();\n```\n\n次のコマンドを使用して実行します。\n\n```bash\nnpx tsx weather-assistant.ts\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n`weather_assistant.py`を作成します。\n\n```python\nimport asyncio\nimport random\nimport sys\nfrom copilot import CopilotClient\nfrom copilot.session import PermissionHandler\nfrom copilot.tools import define_tool\nfrom copilot.session_events import SessionEventType\nfrom pydantic import BaseModel, Field\n\nclass GetWeatherParams(BaseModel):\n    city: str = Field(description=\"The name of the city to get weather for\")\n\n@define_tool(description=\"Get the current weather for a city\")\nasync def get_weather(params: GetWeatherParams) -> dict:\n    city = params.city\n    conditions = [\"sunny\", \"cloudy\", \"rainy\", \"partly cloudy\"]\n    temp = random.randint(50, 80)\n    condition = random.choice(conditions)\n    return {\"city\": city, \"temperature\": f\"{temp}°F\", \"condition\": condition}\n\nasync def main():\n    client = CopilotClient()\n    await client.start()\n\n    session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model=\"auto\", streaming=True, tools=[get_weather])\n\n    def handle_event(event):\n        if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:\n            sys.stdout.write(event.data.delta_content)\n            sys.stdout.flush()\n\n    session.on(handle_event)\n\n    print(\"🌤️  Weather Assistant (type 'exit' to quit)\")\n    print(\"   Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\\n\")\n\n    while True:\n        try:\n            user_input = input(\"You: \")\n        except EOFError:\n            break\n\n        if user_input.lower() == \"exit\":\n            break\n\n        sys.stdout.write(\"Assistant: \")\n        await session.send_and_wait(user_input)\n        print(\"\\n\")\n\n    await client.stop()\n\nasyncio.run(main())\n```\n\n次のコマンドを使用して実行します。\n\n```bash\npython weather_assistant.py\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n`weather-assistant.go`を作成します。\n\n```golang\npackage main\n\nimport (\n    \"bufio\"\n    \"context\"\n    \"fmt\"\n    \"log\"\n    \"math/rand\"\n    \"os\"\n    \"strings\"\n\n    copilot \"github.com/github/copilot-sdk/go\"\n)\n\ntype WeatherParams struct {\n    City string `json:\"city\" jsonschema:\"The city name\"`\n}\n\ntype WeatherResult struct {\n    City        string `json:\"city\"`\n    Temperature string `json:\"temperature\"`\n    Condition   string `json:\"condition\"`\n}\n\nfunc main() {\n    ctx := context.Background()\n\n    getWeather := copilot.DefineTool(\n        \"get_weather\",\n        \"Get the current weather for a city\",\n        func(params WeatherParams, inv copilot.ToolInvocation) (WeatherResult, error) {\n            conditions := []string{\"sunny\", \"cloudy\", \"rainy\", \"partly cloudy\"}\n            temp := rand.Intn(30) + 50\n            condition := conditions[rand.Intn(len(conditions))]\n            return WeatherResult{\n                City:        params.City,\n                Temperature: fmt.Sprintf(\"%d°F\", temp),\n                Condition:   condition,\n            }, nil\n        },\n    )\n\n    client := copilot.NewClient(nil)\n    if err := client.Start(ctx); err != nil {\n        log.Fatal(err)\n    }\n    defer client.Stop()\n\n    session, err := client.CreateSession(ctx, &copilot.SessionConfig{\n        Model:     \"auto\",\n        Streaming: copilot.Bool(true),\n        Tools:     []copilot.Tool{getWeather},\n    })\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    session.On(func(event copilot.SessionEvent) {\n        switch d := event.Data.(type) {\n        case *copilot.AssistantMessageDeltaData:\n            fmt.Print(d.DeltaContent)\n        case *copilot.SessionIdleData:\n            _ = d\n            fmt.Println()\n        }\n    })\n\n    fmt.Println(\"🌤️  Weather Assistant (type 'exit' to quit)\")\n    fmt.Println(\"   Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\\n\")\n\n    scanner := bufio.NewScanner(os.Stdin)\n    for {\n        fmt.Print(\"You: \")\n        if !scanner.Scan() {\n            break\n        }\n        input := scanner.Text()\n        if strings.ToLower(input) == \"exit\" {\n            break\n        }\n\n        fmt.Print(\"Assistant: \")\n        _, err = session.SendAndWait(ctx, copilot.MessageOptions{Prompt: input})\n        if err != nil {\n            fmt.Fprintf(os.Stderr, \"Error: %v\\n\", err)\n            break\n        }\n        fmt.Println()\n    }\n    if err := scanner.Err(); err != nil {\n        fmt.Fprintf(os.Stderr, \"Input error: %v\\n\", err)\n    }\n}\n```\n\n次のコマンドを使用して実行します。\n\n```bash\ngo run weather-assistant.go\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\n`src/main.rs`を作成します。\n\n```rust\nuse std::io::{self, BufRead, Write};\nuse std::sync::Arc;\nuse std::time::Duration;\n\nuse github_copilot_sdk::handler::ApproveAllHandler;\nuse github_copilot_sdk::tool::{define_tool, JsonSchema};\nuse github_copilot_sdk::{Client, ClientOptions, MessageOptions, SessionConfig, ToolResult};\nuse serde::Deserialize;\n\n#[derive(Deserialize, JsonSchema)]\nstruct GetWeatherParams {\n    city: String,\n}\n\nfn read_line() -> Option<String> {\n    let stdin = io::stdin();\n    let mut line = String::new();\n    stdin.lock().read_line(&mut line).ok()?;\n    if line.is_empty() {\n        return None;\n    }\n    Some(line.trim_end_matches(&['\\n', '\\r'][..]).to_string())\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let tools = vec![define_tool(\n        \"get_weather\",\n        \"Get the current weather for a city\",\n        |_inv, params: GetWeatherParams| async move {\n            Ok(ToolResult::Text(format!(\n                \"{}: 62°F and sunny\",\n                params.city\n            )))\n        },\n    )];\n\n    let client = Client::start(ClientOptions::default()).await?;\n\n    let mut config = SessionConfig::default();\n    config.streaming = Some(true);\n    let session = client\n        .create_session(\n            config\n                .with_tools(tools)\n                .with_permission_handler(Arc::new(ApproveAllHandler)),\n        )\n        .await?;\n\n    let mut events = session.subscribe();\n    tokio::spawn(async move {\n        while let Ok(event) = events.recv().await {\n            match event.event_type.as_str() {\n                \"assistant.message_delta\" => {\n                    if let Some(text) =\n                        event.data.get(\"deltaContent\").and_then(|value| value.as_str())\n                    {\n                        print!(\"{text}\");\n                        io::stdout().flush().ok();\n                    }\n                }\n                \"assistant.message\" => println!(),\n                _ => {}\n            }\n        }\n    });\n\n    println!(\"Weather Assistant (type 'exit' to quit)\");\n    println!(\"Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\\n\");\n\n    loop {\n        print!(\"You: \");\n        io::stdout().flush().ok();\n\n        let Some(input) = read_line() else { break };\n        if input.eq_ignore_ascii_case(\"exit\") {\n            break;\n        }\n\n        print!(\"Assistant: \");\n        io::stdout().flush().ok();\n        session\n            .send_and_wait(MessageOptions::new(input).with_wait_timeout(Duration::from_secs(120)))\n            .await?;\n        println!();\n    }\n\n    session.disconnect().await?;\n    client.stop().await?;\n    Ok(())\n}\n```\n\n次のコマンドを使用して実行します。\n\n```bash\ncargo run\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n新しいコンソール プロジェクトを作成し、 `Program.cs`を更新します。\n\n```csharp\nusing GitHub.Copilot;\nusing Microsoft.Extensions.AI;\nusing System.ComponentModel;\n\n// Define the weather tool\nvar getWeather = CopilotTool.DefineTool(\n    ([Description(\"The city name\")] string city) =>\n    {\n        var conditions = new[] { \"sunny\", \"cloudy\", \"rainy\", \"partly cloudy\" };\n        var temp = Random.Shared.Next(50, 80);\n        var condition = conditions[Random.Shared.Next(conditions.Length)];\n        return new { city, temperature = $\"{temp}°F\", condition };\n    },\n    factoryOptions: new AIFunctionFactoryOptions\n    {\n        Name = \"get_weather\",\n        Description = \"Get the current weather for a city\",\n    });\n\nawait using var client = new CopilotClient();\nawait using var session = await client.CreateSessionAsync(new SessionConfig\n{\n    Model = \"auto\",\n    OnPermissionRequest = PermissionHandler.ApproveAll,\n    Streaming = true,\n    Tools = [getWeather]\n});\n\n// Listen for response chunks\nsession.On<SessionEvent>(ev =>\n{\n    if (ev is AssistantMessageDeltaEvent deltaEvent)\n    {\n        Console.Write(deltaEvent.Data.DeltaContent);\n    }\n    if (ev is SessionIdleEvent)\n    {\n        Console.WriteLine();\n    }\n});\n\nConsole.WriteLine(\"🌤️  Weather Assistant (type 'exit' to quit)\");\nConsole.WriteLine(\"   Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\\n\");\n\nwhile (true)\n{\n    Console.Write(\"You: \");\n    var input = Console.ReadLine();\n\n    if (string.IsNullOrEmpty(input) || input.Equals(\"exit\", StringComparison.OrdinalIgnoreCase))\n    {\n        break;\n    }\n\n    Console.Write(\"Assistant: \");\n    await session.SendAndWaitAsync(new MessageOptions { Prompt = input });\n    Console.WriteLine(\"\\n\");\n}\n```\n\n次のコマンドを使用して実行します。\n\n```bash\ndotnet run\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n`WeatherAssistant.java`を作成します。\n\n<!-- docs-validate: skip -->\n\n```java\nimport com.github.copilot.CopilotClient;\nimport com.github.copilot.rpc.*;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.Scanner;\nimport java.util.concurrent.CompletableFuture;\n\npublic class WeatherAssistant {\n    public static void main(String[] args) throws Exception {\n        var random = new Random();\n        var conditions = List.of(\"sunny\", \"cloudy\", \"rainy\", \"partly cloudy\");\n\n        var getWeather = ToolDefinition.create(\n            \"get_weather\",\n            \"Get the current weather for a city\",\n            Map.of(\n                \"type\", \"object\",\n                \"properties\", Map.of(\n                    \"city\", Map.of(\"type\", \"string\", \"description\", \"The city name\")\n                ),\n                \"required\", List.of(\"city\")\n            ),\n            invocation -> {\n                var city = (String) invocation.getArguments().get(\"city\");\n                var temp = random.nextInt(30) + 50;\n                var condition = conditions.get(random.nextInt(conditions.size()));\n                return CompletableFuture.completedFuture(Map.of(\n                    \"city\", city,\n                    \"temperature\", temp + \"°F\",\n                    \"condition\", condition\n                ));\n            }\n        );\n\n        try (var client = new CopilotClient()) {\n            client.start().get();\n\n            var session = client.createSession(\n                new SessionConfig()\n                    .setModel(\"auto\")\n                    .setStreaming(true)\n                    .setOnPermissionRequest(request ->\n                        CompletableFuture.completedFuture(PermissionDecision.allow())\n                    )\n                    .setTools(List.of(getWeather))\n            ).get();\n\n            session.on(AssistantMessageDeltaEvent.class, delta -> {\n                System.out.print(delta.getData().deltaContent());\n            });\n            session.on(SessionIdleEvent.class, idle -> {\n                System.out.println();\n            });\n\n            System.out.println(\"🌤️  Weather Assistant (type 'exit' to quit)\");\n            System.out.println(\"   Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\\n\");\n\n            var scanner = new Scanner(System.in);\n            while (true) {\n                System.out.print(\"You: \");\n                if (!scanner.hasNextLine()) break;\n                var input = scanner.nextLine();\n                if (input.equalsIgnoreCase(\"exit\")) break;\n\n                System.out.print(\"Assistant: \");\n                session.sendAndWait(\n                    new MessageOptions().setPrompt(input)\n                ).get();\n                System.out.println(\"\\n\");\n            }\n\n            client.stop().get();\n        }\n    }\n}\n```\n\n次のコマンドを使用して実行します。\n\n```bash\njavac -cp copilot-sdk.jar WeatherAssistant.java && java -cp .:copilot-sdk.jar WeatherAssistant\n```\n\n</div>\n\n</div>\n\n**セッションの例:**\n\n```text\n🌤️  Weather Assistant (type 'exit' to quit)\n   Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\n\nYou: What's the weather in Seattle?\nAssistant: Let me check the weather for Seattle...\nIt's currently 62°F and cloudy in Seattle.\n\nYou: How about Tokyo and London?\nAssistant: I'll check both cities for you:\n- Tokyo: 75°F and sunny\n- London: 58°F and rainy\n\nYou: exit\n```\n\nCopilot呼び出し可能なカスタム ツールを使用してアシスタントを構築しました。\n\n## ツールのしくみ\n\nツールを定義するということは、Copilot に次のことを伝えていることになります:\n\n1. **ツールの機能** (説明)\n2. **必要なパラメーター** (スキーマ)\n3. **実行するコード** (ハンドラー)\n\nCopilotは、ユーザーの質問に基づいてツールを呼び出すタイミングを決定します。 その場合:\n\n1. Copilot はパラメーターを使用してツール呼び出し要求を送信します\n2. SDK によってハンドラー関数が実行されます\n3. 結果はCopilotに送り返されます\n4. Copilotは結果を応答に組み込みます\n\n## 次は何ですか?\n\n基本を理解したところで、さらに便利な機能をご紹介します:\n\n### MCP サーバーに接続する\n\nMCP (モデル コンテキスト プロトコル) サーバーには、事前構築済みのツールが用意されています。 GitHubの MCP サーバーに接続して、リポジトリ、問題、プル要求にCopilotアクセスできるようにします。\n\n```typescript\nconst session = await client.createSession({\n    mcpServers: {\n        github: {\n            type: \"http\",\n            url: \"https://api.githubcopilot.com/mcp/\",\n        },\n    },\n});\n```\n\n📖\n\\*\\*\n[GitHub Copilot SDK での MCP サーバーの使用](/ja/copilot/how-tos/copilot-sdk/features/mcp)\\*\\* - ローカル サーバーとリモート サーバー、すべての構成オプション、トラブルシューティングについて説明します。\n\n### カスタム エージェントを作成する\n\n特定のタスクに特化した AI ペルソナを定義します。\n\n```typescript\nconst session = await client.createSession({\n    customAgents: [{\n        name: \"pr-reviewer\",\n        displayName: \"PR Reviewer\",\n        description: \"Reviews pull requests for best practices\",\n        prompt: \"You are an expert code reviewer. Focus on security, performance, and maintainability.\",\n    }],\n});\n```\n\n> \\[!TIP]\n> セッション構成で `agent: \"pr-reviewer\"` を設定して、最初からこのエージェントを事前に選択することもできます。 詳細については、 [カスタム エージェントとサブエージェント オーケストレーション](/ja/copilot/how-tos/copilot-sdk/features/custom-agents#selecting-an-agent-at-session-creation) を参照してください。\n\n### システム メッセージをカスタマイズする\n\n指示を追加することで、AI の動作と個性を制御します。\n\n```typescript\nconst session = await client.createSession({\n    systemMessage: {\n        content: \"You are a helpful assistant for our engineering team. Always be concise.\",\n    },\n});\n```\n\nより詳細な制御を行うには、 `mode: \"customize\"` を使用して、残りの部分を維持しながら、システム プロンプトの個々のセクションをオーバーライドします。\n\n```typescript\nconst session = await client.createSession({\n    systemMessage: {\n        mode: \"customize\",\n        sections: {\n            tone: { action: \"replace\", content: \"Respond in a warm, professional tone. Be thorough in explanations.\" },\n            code_change_rules: { action: \"remove\" },\n            guidelines: { action: \"append\", content: \"\\n* Always cite data sources\" },\n        },\n        content: \"Focus on financial analysis and reporting.\",\n    },\n});\n```\n\n使用可能なセクション ID: `preamble`、 `identity`、 `tone`、 `tool_efficiency`、 `environment_context`、 `code_change_rules`、 `guidelines`、 `safety`、 `tool_instructions`、 `custom_instructions`、 `runtime_instructions`、 `last_instructions`。\n\n`identity` および `tool_instructions` はセクション *グループ*です。関連するサブセクションのコレクションを 1 つの単位として対象とします。\n`preamble`を使用して、兄弟サブセクションに影響を与えずに ID プリアンブルのみを対象とします。\n\n各オーバーライドでは、 `replace`、 `remove`、 `append`、 `prepend`、 `preserve`の 5 つのアクションがサポートされます。\n`preserve` アクションは、何もしない操作であり、個別にアドレス指定できるセクションをグループ レベルの `remove` の対象外にします（たとえば、`tone` グループを削除するときに `identity` を保持します）。 不明なセクション ID は適切に処理されます。 `replace`/`append`/`prepend` オーバーライドのコンテンツは追加の命令に追加され、 `remove` オーバーライドは自動的に無視されます。\n\n<c0>TypeScript\\</c0 の例については、言語固有の SDK READM を参照してください> <c1>Python</c1>、<c2>Go</c2>、<c3>Rust</c3>、<c4>Java</c4>、および <c5>C#</c5>。\n\n## 外部 CLI サーバーへの接続\n\n既定では、COPILOT CLI プロセス ライフサイクルが SDK によって自動的に管理され、必要に応じて CLI が開始および停止されます。 ただし、サーバー モードで CLI を個別に実行し、SDK に接続することもできます。 これは、次の場合に役立ちます。\n\n* **デバッグ**: SDK の再起動の間に CLI を実行したままにしてログを検査する\n* **リソース共有**: 複数の SDK クライアントが同じ CLI サーバーに接続できる\n* **開発**: カスタム設定または別の環境で CLI を実行する\n\n### サーバー モードでの CLI の実行\n\n`--headless` フラグを使用してサーバー モードで CLI を起動し、必要に応じてポートを指定します。\n\n```bash\ncopilot --headless --port 4321\n```\n\nポートを指定しない場合、CLI はランダムに使用可能なポートを選択します。\n\n既定では、ヘッドレス サーバーはループバック (`127.0.0.1`) からの接続のみを受け入れるため、SDK は同じコンピューター上で実行する必要があります。 他のホスト (コンテナーまたは別のサーバーで CLI を実行する場合など) からの接続を受け入れるには、 `--host`を使用して非ループバック アドレスにバインドします。\n\n```bash\n# Listen on all interfaces\ncopilot --headless --host 0.0.0.0 --port 4321\n```\n\n> \\[!WARNING]\n> 非ループバック アドレスでヘッドレス サーバーを公開すると、そのアドレスにルーティングできるすべてのユーザーがヘッドレス サーバーに到達できるようになります。 ネットワーク制御 (ファイアウォール、プライベート ネットワーク、リバース プロキシ) と、環境に適した認証と組み合わせてください。\n\n### 外部サーバーへの SDK の接続\n\nCLI がサーバー モードで実行されたら、\"cli url\" オプションを使用してそれに接続するように SDK クライアントを構成します。\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\nimport { CopilotClient, approveAll } from \"@github/copilot-sdk\";\n\nconst client = new CopilotClient({\n    cliUrl: \"localhost:4321\"\n});\n\n// Use the client normally\nconst session = await client.createSession({ onPermissionRequest: approveAll });\n// ...\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\nfrom copilot import CopilotClient, RuntimeConnection\nfrom copilot.session import PermissionHandler\n\nclient = CopilotClient(connection=RuntimeConnection.for_uri(\"localhost:4321\"))\nawait client.start()\n\n# Use the client normally\nsession = await client.create_session(on_permission_request=PermissionHandler.approve_all)\n# ...\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\nimport copilot \"github.com/github/copilot-sdk/go\"\n\nclient := copilot.NewClient(&copilot.ClientOptions{\n    Connection: copilot.URIConnection{URL: \"localhost:4321\"},\n})\n\nif err := client.Start(ctx); err != nil {\n    log.Fatal(err)\n}\ndefer client.Stop()\n\n// Use the client normally\nsession, err := client.CreateSession(ctx, &copilot.SessionConfig{\n    OnPermissionRequest: copilot.PermissionHandler.ApproveAll,\n})\n// ...\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\n```rust\nuse std::sync::Arc;\n\nuse github_copilot_sdk::handler::ApproveAllHandler;\nuse github_copilot_sdk::{Client, ClientOptions, SessionConfig, Transport};\n\nlet mut options = ClientOptions::default();\noptions.transport = Transport::External {\n    host: \"localhost\".to_string(),\n    port: 4321,\n    connection_token: None,\n};\nlet client = Client::start(options).await?;\n\n// Use the client normally\nlet session = client\n    .create_session(SessionConfig::default().with_permission_handler(Arc::new(ApproveAllHandler)))\n    .await?;\n// ...\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\nusing GitHub.Copilot;\n\nusing var client = new CopilotClient(new CopilotClientOptions\n{\n    Connection = RuntimeConnection.ForUri(\"localhost:4321\"),\n});\n\n// Use the client normally\nawait using var session = await client.CreateSessionAsync(new()\n{\n    OnPermissionRequest = PermissionHandler.ApproveAll\n});\n// ...\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n```java\nimport com.github.copilot.CopilotClient;\nimport com.github.copilot.rpc.*;\n\nvar client = new CopilotClient(\n    new CopilotClientOptions().setCliUrl(\"localhost:4321\")\n);\nclient.start().get();\n\n// Use the client normally\nvar session = client.createSession(\n    new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)\n).get();\n// ...\n```\n\n</div>\n\n</div>\n\n**メモ：**`cli_url` / `cliUrl`/Go の`URIConnection`が提供されている場合、または Rust が`Transport::External`を使用している場合、SDK は CLI プロセスを生成または管理しません。指定された URL にある既存のサーバーにのみ接続されます。\n\n## テレメトリと可観測性\n\nCopilot SDK では、分散トレースの [OpenTelemetry](https://opentelemetry.io/) がサポートされています。 CLI プロセスからのトレース エクスポートと、SDK と CLI 間の `telemetry`の自動伝達を有効にする[](https://www.w3.org/TR/trace-context/)構成をクライアントに提供します。\n\n### テレメトリの有効化\n\nクライアントの作成時に `telemetry` (または `Telemetry`) 構成を渡します。 これはオプトインです。個別の \"有効\" フラグは必要ありません。\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n<!-- docs-validate: skip -->\n\n```typescript\nimport { CopilotClient } from \"@github/copilot-sdk\";\n\nconst client = new CopilotClient({\n  telemetry: {\n    otlpEndpoint: \"http://localhost:4318\",\n  },\n});\n```\n\nオプションのピア依存関係: `@opentelemetry/api`\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n<!-- docs-validate: skip -->\n\n```python\nfrom copilot import CopilotClient, CopilotClientOptions\n\nclient = CopilotClient(CopilotClientOptions(\n    telemetry={\n        \"otlp_endpoint\": \"http://localhost:4318\",\n    },\n))\n```\n\nテレメトリの追加機能を使用してインストールする: `pip install copilot-sdk[telemetry]` ( `opentelemetry-api`を提供)\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n<!-- docs-validate: skip -->\n\n```golang\nclient := copilot.NewClient(&copilot.ClientOptions{\n    Telemetry: &copilot.TelemetryConfig{\n        OTLPEndpoint: \"http://localhost:4318\",\n    },\n})\n```\n\n依存 関係： `go.opentelemetry.io/otel`\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\n<!-- docs-validate: skip -->\n\n```rust\nuse github_copilot_sdk::{Client, ClientOptions, OtelExporterType, TelemetryConfig};\n\nlet mut options = ClientOptions::default();\noptions.telemetry = Some(\n    TelemetryConfig::new()\n        .with_exporter_type(OtelExporterType::OtlpHttp)\n        .with_otlp_endpoint(\"http://localhost:4318\"),\n);\nlet client = Client::start(options).await?;\n```\n\n追加の依存関係はありません。SDK は、生成された CLI プロセス用のテレメトリ環境変数を挿入します。\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n<!-- docs-validate: skip -->\n\n```csharp\nvar client = new CopilotClient(new CopilotClientOptions\n{\n    Telemetry = new TelemetryConfig\n    {\n        OtlpEndpoint = \"http://localhost:4318\",\n    },\n});\n```\n\n追加の依存関係はありません。組み込みの `System.Diagnostics.Activity`を使用します。\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n<!-- docs-validate: skip -->\n\n```java\nimport com.github.copilot.CopilotClient;\nimport com.github.copilot.rpc.*;\n\nvar client = new CopilotClient(new CopilotClientOptions()\n    .setTelemetry(new TelemetryConfig()\n        .setOtlpEndpoint(\"http://localhost:4318\")));\n```\n\n依存 関係： `io.opentelemetry:opentelemetry-api`\n\n</div>\n\n</div>\n\n### TelemetryConfig オプション\n\n| オプション                      | Node.js          | Python            | Go               | Rust              | Java             | .NET             | Description                                                    |\n| -------------------------- | ---------------- | ----------------- | ---------------- | ----------------- | ---------------- | ---------------- | -------------------------------------------------------------- |\n| OTLP エンドポイント               | `otlpEndpoint`   | `otlp_endpoint`   | `OTLPEndpoint`   | `otlp_endpoint`   | `otlpEndpoint`   | `OtlpEndpoint`   | OTLP HTTP エンドポイント URL                                          |\n| OTLP プロトコル                 | `otlpProtocol`   | `otlp_protocol`   | `OTLPProtocol`   | `otlp_protocol`   | `otlpProtocol`   | `OtlpProtocol`   | すべてのシグナルの OTLP HTTP プロトコル: `\"http/json\"` または `\"http/protobuf\"` |\n| ファイルパス                     | `filePath`       | `file_path`       | `FilePath`       | `file_path`       | `filePath`       | `FilePath`       | JSON 行トレース出力のファイル パス                                           |\n| エクスポーターの種類                 | `exporterType`   | `exporter_type`   | `ExporterType`   | `exporter_type`   | `exporterType`   | `ExporterType`   |                                                                |\n| `\"otlp-http\"` または `\"file\"` |                  |                   |                  |                   |                  |                  |                                                                |\n| 求人者名                       | `sourceName`     | `source_name`     | `SourceName`     | `source_name`     | `sourceName`     | `SourceName`     | 計装範囲名                                                          |\n| コンテンツをキャプチャする              | `captureContent` | `capture_content` | `CaptureContent` | `capture_content` | `captureContent` | `CaptureContent` | メッセージの内容をキャプチャするかどうか                                           |\n\nOTLP プロトコル フィールドは、すべての信号に対して CLI の `\"otlp-http\"` エクスポーターを構成します。 CLI の既定値を使用するように設定したままにするか、http 経由で protobuf をエクスポートする `\"http/protobuf\"` に設定します。\n\n### ファイルのエクスポート\n\nOTLP エンドポイントの代わりにローカル ファイルにトレースを書き込むには、\n\n<!-- docs-validate: skip -->\n\n```typescript\nconst client = new CopilotClient({\n  telemetry: {\n    filePath: \"./traces.jsonl\",\n    exporterType: \"file\",\n  },\n});\n```\n\n### トレース コンテキストの伝達\n\nトレース コンテキストは自動的に伝達されます。手動によるインストルメンテーションは必要ありません。\n\n* **SDK → CLI**: 現在のスパン/アクティビティの `traceparent` ヘッダーと `tracestate` ヘッダーは、`session.create`、`session.resume`、および `session.send` RPC 呼び出しに含まれます。\n* **CLI → SDK**: CLI がツール ハンドラーを呼び出すと、CLI のスパンからのトレース コンテキストが伝達され、ツール コードが正しい親スパンで実行されます。\n\n📖\n\\*\\*\n[Copilot SDK 用の OpenTelemetry インストルメンテーション](/ja/copilot/how-tos/copilot-sdk/observability/opentelemetry)\\*\\* - TelemetryConfig オプション、トレース コンテキスト伝達、および言語ごとの依存関係。\n\n## 詳細情報\n\n* [認証](/ja/copilot/how-tos/copilot-sdk/auth/authenticate) - GitHub OAuth、環境変数、BYOK\n* [BYOK (独自のキーを持ち込む)](/ja/copilot/how-tos/copilot-sdk/auth/byok) - Microsoft Foundry、OpenAI などの独自の API キーを使用します。\n* [Node.js SDK リファレンス](https://github.com/github/copilot-sdk/tree/main/nodejs/README.md)\n* [Python SDK リファレンス](https://github.com/github/copilot-sdk/tree/main/python/README.md)\n* [Go SDK リファレンス](https://github.com/github/copilot-sdk/tree/main/go/README.md)\n* [Rust SDK リファレンス](https://github.com/github/copilot-sdk/tree/main/rust/README.md)\n* [.NET SDK リファレンス](https://github.com/github/copilot-sdk/tree/main/dotnet/README.md)\n* [Java SDK リファレンス](https://github.com/github/copilot-sdk/tree/main/java/README.md)\n* [GitHub Copilot SDK での MCP サーバーの使用](/ja/copilot/how-tos/copilot-sdk/features/mcp) - モデル コンテキスト プロトコルを使用して外部ツールを統合する\n* [GitHub MCP サーバーのドキュメント](https://github.com/github/github-mcp-server)\n* [MCP サーバー ディレクトリ](https://github.com/modelcontextprotocol/servers) - MCP サーバーの詳細を確認する\n* [Copilot SDK 用の OpenTelemetry インストルメンテーション](/ja/copilot/how-tos/copilot-sdk/observability/opentelemetry) - TelemetryConfig、トレース コンテキストの伝達、言語ごとの依存関係\n\n**それをやりました！** GitHub Copilot SDK の主要な概念を学習しました。\n\n* ✅ クライアントとセッションの作成\n* ✅ メッセージの送信と応答の受信\n* ✅ リアルタイム出力のためのストリーミング\n* ✅ Copilot が呼び出せるカスタム ツールを定義する\n\n今、素晴らしい何かを構築に行く!\n🚀"}