# 初めてのCopilot搭載アプリを構築する

このチュートリアルでは、Copilot SDK を使用してコマンド ライン アシスタントを構築します。 基本から始めて、ストリーミング応答を追加し、その後カスタム ツールを追加して、Copilot にコードを呼び出す機能を与えます。

<!-- markdownlint-disable GHD046 GHD005 -->

<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->

**ビルドする内容:**

```text
You: What's the weather like in Seattle?
Copilot: Let me check the weather for Seattle...
         Currently 62°F and cloudy with a chance of rain.
         Typical Seattle weather!

You: How about Tokyo?
Copilot: In Tokyo it's 75°F and sunny. Great day to be outside!
```

## Prerequisites

開始する前に、以下の項目があることを確認します:

* **GitHub Copilot CLI** インストールおよび認証 ([インストール ガイド](/ja/copilot/how-tos/set-up/install-copilot-cli))
* お好みの言語ランタイム:
  * **Node.js** 20+ または **Python** 3.11 以降または **Go** 1.24 以上または> **Rust** 1.94 以上または **Java** 17 以上または **.NET** 8.0 以降

CLI が動作していることを確認します。

```bash
copilot --version
```

## 手順 1: SDK をインストールする

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

まず、新しいディレクトリを作成し、プロジェクトを初期化します。

```bash
mkdir copilot-demo && cd copilot-demo
npm init -y --init-type module
```

次に、SDK と TypeScript ランナーをインストールします。

```bash
npm install @github/copilot-sdk tsx
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

```bash
pip install github-copilot-sdk
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

まず、新しいディレクトリを作成し、モジュールを初期化します。

```bash
mkdir copilot-demo && cd copilot-demo
go mod init copilot-demo
```

次に、SDK をインストールします。

```bash
go get github.com/github/copilot-sdk/go
```

</div>

<div class="ghd-codetab" data-lang="rust" data-label="Rust"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Rust</div>

まず、新しいバイナリ クレートを作成します。

```bash
cargo new copilot-demo && cd copilot-demo
```

次に、例で使用される SDK と直接の依存関係をインストールします。

```bash
cargo add github-copilot-sdk --features derive
# Used by #[tokio::main] and tokio::spawn
cargo add tokio --features rt-multi-thread,macros
# Used by custom-tool parameter derives later in this guide
cargo add serde --features derive
cargo add schemars
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

まず、新しいコンソール プロジェクトを作成します。

```bash
dotnet new console -n CopilotDemo && cd CopilotDemo
```

次に、SDK を追加します。

```bash
dotnet add package GitHub.Copilot.SDK
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

まず、新しいディレクトリを作成し、プロジェクトを初期化します。

**Maven** — `pom.xml`に追加します。

```xml
<dependency>
    <groupId>com.github</groupId>
    <artifactId>copilot-sdk-java</artifactId>
    <version>${copilot.sdk.version}</version>
</dependency>
```

**Gradle** — `build.gradle`に追加します。

```groovy
implementation 'com.github:copilot-sdk-java:${copilotSdkVersion}'
```

</div>

</div>

## 手順 2: 最初のメッセージを送信する

新しいファイルを作成し、次のコードを追加します。 これは、SDK (約 5 行のコード) を使用する最も簡単な方法です。

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

`index.ts`を作成します。

```typescript
import { CopilotClient } from "@github/copilot-sdk";

const client = new CopilotClient();
const session = await client.createSession({ model: "gpt-4.1" });

const response = await session.sendAndWait({ prompt: "What is 2 + 2?" });
console.log(response?.data.content);

await client.stop();
process.exit(0);
```

次のコマンドを実行します。

```bash
npx tsx index.ts
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

`main.py`を作成します。

```python
import asyncio
from copilot import CopilotClient
from copilot.session import PermissionHandler

async def main():
    client = CopilotClient()
    await client.start()

    session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model="gpt-4.1")
    response = await session.send_and_wait("What is 2 + 2?")
    print(response.data.content)

    await client.stop()

asyncio.run(main())
```

次のコマンドを実行します。

```bash
python main.py
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

`main.go`を作成します。

```golang
package main

import (
    "context"
    "fmt"
    "log"
    "os"

    copilot "github.com/github/copilot-sdk/go"
)

func main() {
    ctx := context.Background()
    client := copilot.NewClient(nil)
    if err := client.Start(ctx); err != nil {
        log.Fatal(err)
    }
    defer client.Stop()

    session, err := client.CreateSession(ctx, &copilot.SessionConfig{Model: "gpt-4.1"})
    if err != nil {
        log.Fatal(err)
    }

    response, err := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "What is 2 + 2?"})
    if err != nil {
        log.Fatal(err)
    }

    if d, ok := response.Data.(*copilot.AssistantMessageData); ok {
        fmt.Println(d.Content)
    }
    os.Exit(0)
}
```

次のコマンドを実行します。

```bash
go run main.go
```

</div>

<div class="ghd-codetab" data-lang="rust" data-label="Rust"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Rust</div>

`src/main.rs`を作成します。

```rust
use std::sync::Arc;
use std::time::Duration;

use github_copilot_sdk::handler::ApproveAllHandler;
use github_copilot_sdk::{Client, ClientOptions, MessageOptions, SessionConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::start(ClientOptions::default()).await?;
    let session = client
        .create_session(SessionConfig::default().with_handler(Arc::new(ApproveAllHandler)))
        .await?;

    let response = session
        .send_and_wait(
            MessageOptions::new("What is 2 + 2?").with_wait_timeout(Duration::from_secs(120)),
        )
        .await?;

    if let Some(event) = response {
        if let Some(content) = event.data.get("content").and_then(|value| value.as_str()) {
            println!("{content}");
        }
    }

    session.disconnect().await?;
    client.stop().await?;
    Ok(())
}
```

次のコマンドを実行します。

```bash
cargo run
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

新しいコンソール プロジェクトを作成し、これを `Program.cs`に追加します。

```csharp
using GitHub.Copilot;

await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-4.1",
    OnPermissionRequest = PermissionHandler.ApproveAll
});

var response = await session.SendAndWaitAsync(new MessageOptions { Prompt = "What is 2 + 2?" });
Console.WriteLine(response?.Data.Content);
```

次のコマンドを実行します。

```bash
dotnet run
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

`HelloCopilot.java`を作成します。

```java
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.events.*;
import com.github.copilot.sdk.json.*;

public class HelloCopilot {
    public static void main(String[] args) throws Exception {
        try (var client = new CopilotClient()) {
            client.start().get();

            var session = client.createSession(
                new SessionConfig()
                    .setModel("gpt-4.1")
                    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
            ).get();

            var response = session.sendAndWait(
                new MessageOptions().setPrompt("What is 2 + 2?")
            ).get();

            System.out.println(response.getData().content());

            client.stop().get();
        }
    }
}
```

次のコマンドを実行します。

```bash
javac -cp copilot-sdk.jar HelloCopilot.java && java -cp .:copilot-sdk.jar HelloCopilot
```

</div>

</div>

**次のように表示されます:**

```text
4
```

おめでとうございます! Copilot を活用したアプリを初めて構築しました。

## 手順 3: ストリーミング応答を追加する

現時点では、何かを表示する前に、完全な応答を待ちます。 生成された応答をストリーミングして対話型にしましょう。

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

`index.ts`を更新してください。

```typescript
import { CopilotClient } from "@github/copilot-sdk";

const client = new CopilotClient();
const session = await client.createSession({
    model: "gpt-4.1",
    streaming: true,
});

// Listen for response chunks
session.on("assistant.message_delta", (event) => {
    process.stdout.write(event.data.deltaContent);
});
session.on("session.idle", () => {
    console.log(); // New line when done
});

await session.sendAndWait({ prompt: "Tell me a short joke" });

await client.stop();
process.exit(0);
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

`main.py`を更新してください。

```python
import asyncio
import sys
from copilot import CopilotClient
from copilot.session import PermissionHandler
from copilot.generated.session_events import SessionEventType

async def main():
    client = CopilotClient()
    await client.start()

    session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model="gpt-4.1", streaming=True)

    # Listen for response chunks
    def handle_event(event):
        if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:
            sys.stdout.write(event.data.delta_content)
            sys.stdout.flush()
        if event.type == SessionEventType.SESSION_IDLE:
            print()  # New line when done

    session.on(handle_event)

    await session.send_and_wait("Tell me a short joke")

    await client.stop()

asyncio.run(main())
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

`main.go`を更新してください。

```golang
package main

import (
    "context"
    "fmt"
    "log"
    "os"

    copilot "github.com/github/copilot-sdk/go"
)

func main() {
    ctx := context.Background()
    client := copilot.NewClient(nil)
    if err := client.Start(ctx); err != nil {
        log.Fatal(err)
    }
    defer client.Stop()

    session, err := client.CreateSession(ctx, &copilot.SessionConfig{
        Model:     "gpt-4.1",
        Streaming: copilot.Bool(true),
    })
    if err != nil {
        log.Fatal(err)
    }

    // Listen for response chunks
    session.On(func(event copilot.SessionEvent) {
        switch d := event.Data.(type) {
        case *copilot.AssistantMessageDeltaData:
            fmt.Print(d.DeltaContent)
        case *copilot.SessionIdleData:
            _ = d
            fmt.Println()
        }
    })

    _, err = session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Tell me a short joke"})
    if err != nil {
        log.Fatal(err)
    }
    os.Exit(0)
}
```

</div>

<div class="ghd-codetab" data-lang="rust" data-label="Rust"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Rust</div>

`src/main.rs`を更新してください。

```rust
use std::io::{self, Write};
use std::sync::Arc;
use std::time::Duration;

use github_copilot_sdk::handler::ApproveAllHandler;
use github_copilot_sdk::{Client, ClientOptions, MessageOptions, SessionConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::start(ClientOptions::default()).await?;

    let mut config = SessionConfig::default();
    config.streaming = Some(true);
    let session = client
        .create_session(config.with_handler(Arc::new(ApproveAllHandler)))
        .await?;

    // Listen for response chunks
    let mut events = session.subscribe();
    tokio::spawn(async move {
        while let Ok(event) = events.recv().await {
            match event.event_type.as_str() {
                "assistant.message_delta" => {
                    if let Some(text) =
                        event.data.get("deltaContent").and_then(|value| value.as_str())
                    {
                        print!("{text}");
                        io::stdout().flush().ok();
                    }
                }
                "assistant.message" => println!(),
                _ => {}
            }
        }
    });

    session
        .send_and_wait(
            MessageOptions::new("Tell me a short joke")
                .with_wait_timeout(Duration::from_secs(120)),
        )
        .await?;

    session.disconnect().await?;
    client.stop().await?;
    Ok(())
}
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

`Program.cs`を更新してください。

```csharp
using GitHub.Copilot;

await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-4.1",
    OnPermissionRequest = PermissionHandler.ApproveAll,
    Streaming = true,
});

// Listen for response chunks
session.On<SessionEvent>(ev =>
{
    if (ev is AssistantMessageDeltaEvent deltaEvent)
    {
        Console.Write(deltaEvent.Data.DeltaContent);
    }
    if (ev is SessionIdleEvent)
    {
        Console.WriteLine();
    }
});

await session.SendAndWaitAsync(new MessageOptions { Prompt = "Tell me a short joke" });
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

`HelloCopilot.java`を更新してください。

```java
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.events.*;
import com.github.copilot.sdk.json.*;

public class HelloCopilot {
    public static void main(String[] args) throws Exception {
        try (var client = new CopilotClient()) {
            client.start().get();

            var session = client.createSession(
                new SessionConfig()
                    .setModel("gpt-4.1")
                    .setStreaming(true)
                    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
            ).get();

            // Listen for response chunks
            session.on(AssistantMessageDeltaEvent.class, delta -> {
                System.out.print(delta.getData().deltaContent());
            });
            session.on(SessionIdleEvent.class, idle -> {
                System.out.println(); // New line when done
            });

            session.sendAndWait(
                new MessageOptions().setPrompt("Tell me a short joke")
            ).get();

            client.stop().get();
        }
    }
}
```

</div>

</div>

コードをもう一度実行します。 応答が単語ごとに表示されます。

### イベント サブスクリプションメソッド

SDK には、セッション イベントをサブスクライブするためのメソッドが用意されています。

| Method                   | Description                                                        |
| ------------------------ | ------------------------------------------------------------------ |
| `on(handler)`            | すべてのイベントをサブスクライブする。unsubscribe 関数を返します                             |
| `on(eventType, handler)` | 特定のイベントの種類 (Node.js/TypeScript のみ) をサブスクライブします。unsubscribe 関数を返します |
| `subscribe()`            | すべてのイベントを購読する (Rust); `event_type` で絞り込む                           |

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

```typescript
// Subscribe to all events
const unsubscribeAll = session.on((event) => {
    console.log("Event:", event.type);
});

// Subscribe to specific event type
const unsubscribeIdle = session.on("session.idle", (event) => {
    console.log("Session is idle");
});

// Later, to unsubscribe:
unsubscribeAll();
unsubscribeIdle();
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

```python
from copilot import CopilotClient, PermissionDecisionApproveOnce
from copilot.generated.session_events import SessionEvent, SessionEventType

client = CopilotClient()

session = await client.create_session(on_permission_request=lambda req, inv: PermissionDecisionApproveOnce())

# Subscribe to all events
unsubscribe = session.on(lambda event: print(f"Event: {event.type}"))

# Filter by event type in your handler
def handle_event(event: SessionEvent) -> None:
    if event.type == SessionEventType.SESSION_IDLE:
        print("Session is idle")
    elif event.type == SessionEventType.ASSISTANT_MESSAGE:
        print(f"Message: {event.data.content}")

unsubscribe = session.on(handle_event)

# Later, to unsubscribe:
unsubscribe()
```

```python
# Subscribe to all events
unsubscribe = session.on(lambda event: print(f"Event: {event.type}"))

# Filter by event type in your handler
def handle_event(event):
    if event.type == SessionEventType.SESSION_IDLE:
        print("Session is idle")
    elif event.type == SessionEventType.ASSISTANT_MESSAGE:
        print(f"Message: {event.data.content}")

unsubscribe = session.on(handle_event)

# Later, to unsubscribe:
unsubscribe()
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

```golang
package main

import (
    "fmt"

    copilot "github.com/github/copilot-sdk/go"
)

func main() {
    session := &copilot.Session{}

    // Subscribe to all events
    unsubscribe := session.On(func(event copilot.SessionEvent) {
        fmt.Println("Event:", event.Type)
    })

    // Filter by event type in your handler
    session.On(func(event copilot.SessionEvent) {
        switch d := event.Data.(type) {
        case *copilot.SessionIdleData:
            _ = d
            fmt.Println("Session is idle")
        case *copilot.AssistantMessageData:
            fmt.Println("Message:", d.Content)
        }
    })

    // Later, to unsubscribe:
    unsubscribe()
}
```

```golang
// Subscribe to all events
unsubscribe := session.On(func(event copilot.SessionEvent) {
    fmt.Println("Event:", event.Type)
})

// Filter by event type in your handler
session.On(func(event copilot.SessionEvent) {
    switch d := event.Data.(type) {
    case *copilot.SessionIdleData:
        _ = d
        fmt.Println("Session is idle")
    case *copilot.AssistantMessageData:
        fmt.Println("Message:", d.Content)
    }
})

// Later, to unsubscribe:
unsubscribe()
```

</div>

<div class="ghd-codetab" data-lang="rust" data-label="Rust"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Rust</div>

```rust
let mut events = session.subscribe();

tokio::spawn(async move {
    while let Ok(event) = events.recv().await {
        println!("Event: {}", event.event_type);

        match event.event_type.as_str() {
            "session.idle" => println!("Session is idle"),
            "assistant.message" => {
                if let Some(content) = event.data.get("content").and_then(|value| value.as_str()) {
                    println!("Message: {content}");
                }
            }
            _ => {}
        }
    }
});
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

```csharp
using GitHub.Copilot;

public static class EventSubscriptionExample
{
    public static void Example(CopilotSession session)
    {
        // Subscribe to all events
        var unsubscribe = session.On<SessionEvent>(ev => Console.WriteLine($"Event: {ev.Type}"));

        // Filter by event type using pattern matching
        session.On<SessionEvent>(ev =>
        {
            switch (ev)
            {
                case SessionIdleEvent:
                    Console.WriteLine("Session is idle");
                    break;
                case AssistantMessageEvent msg:
                    Console.WriteLine($"Message: {msg.Data.Content}");
                    break;
            }
        });

        // Later, to unsubscribe:
        unsubscribe.Dispose();
    }
}
```

```csharp
// Subscribe to all events
var unsubscribe = session.On<SessionEvent>(ev => Console.WriteLine($"Event: {ev.Type}"));

// Filter by event type using pattern matching
session.On<SessionEvent>(ev =>
{
    switch (ev)
    {
        case SessionIdleEvent:
            Console.WriteLine("Session is idle");
            break;
        case AssistantMessageEvent msg:
            Console.WriteLine($"Message: {msg.Data.Content}");
            break;
    }
});

// Later, to unsubscribe:
unsubscribe.Dispose();
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

```java
// Subscribe to all events
var unsubscribe = session.on(event -> {
    System.out.println("Event: " + event.getType());
});

// Subscribe to a specific event type
session.on(AssistantMessageEvent.class, msg -> {
    System.out.println("Message: " + msg.getData().content());
});

session.on(SessionIdleEvent.class, idle -> {
    System.out.println("Session is idle");
});

// Later, to unsubscribe:
unsubscribe.close();
```

</div>

</div>

## 手順 4: カスタム ツールを追加する

では、ここからが本題です。 Copilotカスタム ツールを定義してコードを呼び出す機能を提供しましょう。 簡単な気象検索ツールを作成します。

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

`index.ts`を更新してください。

```typescript
import { CopilotClient, defineTool } from "@github/copilot-sdk";

// Define a tool that Copilot can call
const getWeather = defineTool("get_weather", {
    description: "Get the current weather for a city",
    parameters: {
        type: "object",
        properties: {
            city: { type: "string", description: "The city name" },
        },
        required: ["city"],
    },
    handler: async (args: { city: string }) => {
        const { city } = args;
        // In a real app, you'd call a weather API here
        const conditions = ["sunny", "cloudy", "rainy", "partly cloudy"];
        const temp = Math.floor(Math.random() * 30) + 50;
        const condition = conditions[Math.floor(Math.random() * conditions.length)];
        return { city, temperature: `${temp}°F`, condition };
    },
});

const client = new CopilotClient();
const session = await client.createSession({
    model: "gpt-4.1",
    streaming: true,
    tools: [getWeather],
});

session.on("assistant.message_delta", (event) => {
    process.stdout.write(event.data.deltaContent);
});

session.on("session.idle", () => {
    console.log(); // New line when done
});

await session.sendAndWait({
    prompt: "What's the weather like in Seattle and Tokyo?",
});

await client.stop();
process.exit(0);
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

`main.py`を更新してください。

```python
import asyncio
import random
import sys
from copilot import CopilotClient
from copilot.session import PermissionHandler
from copilot.tools import define_tool
from copilot.generated.session_events import SessionEventType
from pydantic import BaseModel, Field

# Define the parameters for the tool using Pydantic
class GetWeatherParams(BaseModel):
    city: str = Field(description="The name of the city to get weather for")

# Define a tool that Copilot can call
@define_tool(description="Get the current weather for a city")
async def get_weather(params: GetWeatherParams) -> dict:
    city = params.city
    # In a real app, you'd call a weather API here
    conditions = ["sunny", "cloudy", "rainy", "partly cloudy"]
    temp = random.randint(50, 80)
    condition = random.choice(conditions)
    return {"city": city, "temperature": f"{temp}°F", "condition": condition}

async def main():
    client = CopilotClient()
    await client.start()

    session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model="gpt-4.1", streaming=True, tools=[get_weather])

    def handle_event(event):
        if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:
            sys.stdout.write(event.data.delta_content)
            sys.stdout.flush()
        if event.type == SessionEventType.SESSION_IDLE:
            print()

    session.on(handle_event)

    await session.send_and_wait("What's the weather like in Seattle and Tokyo?")

    await client.stop()

asyncio.run(main())
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

`main.go`を更新してください。

```golang
package main

import (
    "context"
    "fmt"
    "log"
    "math/rand"
    "os"

    copilot "github.com/github/copilot-sdk/go"
)

// Define the parameter type
type WeatherParams struct {
    City string `json:"city" jsonschema:"The city name"`
}

// Define the return type
type WeatherResult struct {
    City        string `json:"city"`
    Temperature string `json:"temperature"`
    Condition   string `json:"condition"`
}

func main() {
    ctx := context.Background()

    // Define a tool that Copilot can call
    getWeather := copilot.DefineTool(
        "get_weather",
        "Get the current weather for a city",
        func(params WeatherParams, inv copilot.ToolInvocation) (WeatherResult, error) {
            // In a real app, you'd call a weather API here
            conditions := []string{"sunny", "cloudy", "rainy", "partly cloudy"}
            temp := rand.Intn(30) + 50
            condition := conditions[rand.Intn(len(conditions))]
            return WeatherResult{
                City:        params.City,
                Temperature: fmt.Sprintf("%d°F", temp),
                Condition:   condition,
            }, nil
        },
    )

    client := copilot.NewClient(nil)
    if err := client.Start(ctx); err != nil {
        log.Fatal(err)
    }
    defer client.Stop()

    session, err := client.CreateSession(ctx, &copilot.SessionConfig{
        Model:     "gpt-4.1",
        Streaming: copilot.Bool(true),
        Tools:     []copilot.Tool{getWeather},
    })
    if err != nil {
        log.Fatal(err)
    }

    session.On(func(event copilot.SessionEvent) {
        switch d := event.Data.(type) {
        case *copilot.AssistantMessageDeltaData:
            fmt.Print(d.DeltaContent)
        case *copilot.SessionIdleData:
            _ = d
            fmt.Println()
        }
    })

    _, err = session.SendAndWait(ctx, copilot.MessageOptions{
        Prompt: "What's the weather like in Seattle and Tokyo?",
    })
    if err != nil {
        log.Fatal(err)
    }
    os.Exit(0)
}
```

</div>

<div class="ghd-codetab" data-lang="rust" data-label="Rust"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Rust</div>

`src/main.rs`を更新してください。

```rust
use std::io::{self, Write};
use std::sync::Arc;
use std::time::Duration;

use github_copilot_sdk::handler::ApproveAllHandler;
use github_copilot_sdk::tool::{JsonSchema, ToolHandlerRouter, define_tool};
use github_copilot_sdk::{Client, ClientOptions, MessageOptions, SessionConfig, ToolResult};
use serde::Deserialize;

#[derive(Deserialize, JsonSchema)]
struct GetWeatherParams {
    city: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Define a tool that Copilot can call
    let router = ToolHandlerRouter::new(
        vec![define_tool(
            "get_weather",
            "Get the current weather for a city",
            |_inv, params: GetWeatherParams| async move {
                Ok(ToolResult::Text(format!(
                    "{}: 62°F and sunny",
                    params.city
                )))
            },
        )],
        Arc::new(ApproveAllHandler),
    );
    let tools = router.tools();

    let client = Client::start(ClientOptions::default()).await?;

    let mut config = SessionConfig::default();
    config.streaming = Some(true);
    config.tools = Some(tools);
    let session = client.create_session(config.with_handler(Arc::new(router))).await?;

    let mut events = session.subscribe();
    tokio::spawn(async move {
        while let Ok(event) = events.recv().await {
            match event.event_type.as_str() {
                "assistant.message_delta" => {
                    if let Some(text) =
                        event.data.get("deltaContent").and_then(|value| value.as_str())
                    {
                        print!("{text}");
                        io::stdout().flush().ok();
                    }
                }
                "assistant.message" => println!(),
                _ => {}
            }
        }
    });

    session
        .send_and_wait(
            MessageOptions::new("What's the weather like in Seattle and Tokyo?")
                .with_wait_timeout(Duration::from_secs(120)),
        )
        .await?;

    session.disconnect().await?;
    client.stop().await?;
    Ok(())
}
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

`Program.cs`を更新してください。

```csharp
using GitHub.Copilot;
using Microsoft.Extensions.AI;
using System.ComponentModel;

await using var client = new CopilotClient();

// Define a tool that Copilot can call
var getWeather = CopilotTool.DefineTool(
    ([Description("The city name")] string city) =>
    {
        // In a real app, you'd call a weather API here
        var conditions = new[] { "sunny", "cloudy", "rainy", "partly cloudy" };
        var temp = Random.Shared.Next(50, 80);
        var condition = conditions[Random.Shared.Next(conditions.Length)];
        return new { city, temperature = $"{temp}°F", condition };
    },
    factoryOptions: new AIFunctionFactoryOptions
    {
        Name = "get_weather",
        Description = "Get the current weather for a city",
    }
);

await using var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-4.1",
    OnPermissionRequest = PermissionHandler.ApproveAll,
    Streaming = true,
    Tools = [getWeather],
});

session.On<SessionEvent>(ev =>
{
    if (ev is AssistantMessageDeltaEvent deltaEvent)
    {
        Console.Write(deltaEvent.Data.DeltaContent);
    }
    if (ev is SessionIdleEvent)
    {
        Console.WriteLine();
    }
});

await session.SendAndWaitAsync(new MessageOptions
{
    Prompt = "What's the weather like in Seattle and Tokyo?",
});
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

`HelloCopilot.java`を更新してください。

```java
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.events.*;
import com.github.copilot.sdk.json.*;

import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CompletableFuture;

public class HelloCopilot {
    public static void main(String[] args) throws Exception {
        var random = new Random();
        var conditions = List.of("sunny", "cloudy", "rainy", "partly cloudy");

        // Define a tool that Copilot can call
        var getWeather = ToolDefinition.create(
            "get_weather",
            "Get the current weather for a city",
            Map.of(
                "type", "object",
                "properties", Map.of(
                    "city", Map.of("type", "string", "description", "The city name")
                ),
                "required", List.of("city")
            ),
            invocation -> {
                var city = (String) invocation.getArguments().get("city");
                var temp = random.nextInt(30) + 50;
                var condition = conditions.get(random.nextInt(conditions.size()));
                return CompletableFuture.completedFuture(Map.of(
                    "city", city,
                    "temperature", temp + "°F",
                    "condition", condition
                ));
            }
        );

        try (var client = new CopilotClient()) {
            client.start().get();

            var session = client.createSession(
                new SessionConfig()
                    .setModel("gpt-4.1")
                    .setStreaming(true)
                    .setTools(List.of(getWeather))
                    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
            ).get();

            session.on(AssistantMessageDeltaEvent.class, delta -> {
                System.out.print(delta.getData().deltaContent());
            });
            session.on(SessionIdleEvent.class, idle -> {
                System.out.println();
            });

            session.sendAndWait(
                new MessageOptions().setPrompt("What's the weather like in Seattle and Tokyo?")
            ).get();

            client.stop().get();
        }
    }
}
```

</div>

</div>

それを実行すると、Copilot がツールを呼び出して天気データを取得し、その結果を返すことがわかります。

## 手順 5: 対話型アシスタントを構築する

すべてを便利な対話型アシスタントにまとめてみましょう。

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

```typescript
import { CopilotClient, defineTool } from "@github/copilot-sdk";
import * as readline from "readline";

const getWeather = defineTool("get_weather", {
    description: "Get the current weather for a city",
    parameters: {
        type: "object",
        properties: {
            city: { type: "string", description: "The city name" },
        },
        required: ["city"],
    },
    handler: async ({ city }) => {
        const conditions = ["sunny", "cloudy", "rainy", "partly cloudy"];
        const temp = Math.floor(Math.random() * 30) + 50;
        const condition = conditions[Math.floor(Math.random() * conditions.length)];
        return { city, temperature: `${temp}°F`, condition };
    },
});

const client = new CopilotClient();
const session = await client.createSession({
    model: "gpt-4.1",
    streaming: true,
    tools: [getWeather],
});

session.on("assistant.message_delta", (event) => {
    process.stdout.write(event.data.deltaContent);
});

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
});

console.log("🌤️  Weather Assistant (type 'exit' to quit)");
console.log("   Try: 'What's the weather in Paris?'\n");

const prompt = () => {
    rl.question("You: ", async (input) => {
        if (input.toLowerCase() === "exit") {
            await client.stop();
            rl.close();
            return;
        }

        process.stdout.write("Assistant: ");
        await session.sendAndWait({ prompt: input });
        console.log("\n");
        prompt();
    });
};

prompt();
```

次のコマンドを使用して実行します。

```bash
npx tsx weather-assistant.ts
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

`weather_assistant.py`を作成します。

```python
import asyncio
import random
import sys
from copilot import CopilotClient
from copilot.session import PermissionHandler
from copilot.tools import define_tool
from copilot.generated.session_events import SessionEventType
from pydantic import BaseModel, Field

class GetWeatherParams(BaseModel):
    city: str = Field(description="The name of the city to get weather for")

@define_tool(description="Get the current weather for a city")
async def get_weather(params: GetWeatherParams) -> dict:
    city = params.city
    conditions = ["sunny", "cloudy", "rainy", "partly cloudy"]
    temp = random.randint(50, 80)
    condition = random.choice(conditions)
    return {"city": city, "temperature": f"{temp}°F", "condition": condition}

async def main():
    client = CopilotClient()
    await client.start()

    session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model="gpt-4.1", streaming=True, tools=[get_weather])

    def handle_event(event):
        if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:
            sys.stdout.write(event.data.delta_content)
            sys.stdout.flush()

    session.on(handle_event)

    print("🌤️  Weather Assistant (type 'exit' to quit)")
    print("   Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\n")

    while True:
        try:
            user_input = input("You: ")
        except EOFError:
            break

        if user_input.lower() == "exit":
            break

        sys.stdout.write("Assistant: ")
        await session.send_and_wait(user_input)
        print("\n")

    await client.stop()

asyncio.run(main())
```

次のコマンドを使用して実行します。

```bash
python weather_assistant.py
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

`weather-assistant.go`を作成します。

```golang
package main

import (
    "bufio"
    "context"
    "fmt"
    "log"
    "math/rand"
    "os"
    "strings"

    copilot "github.com/github/copilot-sdk/go"
)

type WeatherParams struct {
    City string `json:"city" jsonschema:"The city name"`
}

type WeatherResult struct {
    City        string `json:"city"`
    Temperature string `json:"temperature"`
    Condition   string `json:"condition"`
}

func main() {
    ctx := context.Background()

    getWeather := copilot.DefineTool(
        "get_weather",
        "Get the current weather for a city",
        func(params WeatherParams, inv copilot.ToolInvocation) (WeatherResult, error) {
            conditions := []string{"sunny", "cloudy", "rainy", "partly cloudy"}
            temp := rand.Intn(30) + 50
            condition := conditions[rand.Intn(len(conditions))]
            return WeatherResult{
                City:        params.City,
                Temperature: fmt.Sprintf("%d°F", temp),
                Condition:   condition,
            }, nil
        },
    )

    client := copilot.NewClient(nil)
    if err := client.Start(ctx); err != nil {
        log.Fatal(err)
    }
    defer client.Stop()

    session, err := client.CreateSession(ctx, &copilot.SessionConfig{
        Model:     "gpt-4.1",
        Streaming: copilot.Bool(true),
        Tools:     []copilot.Tool{getWeather},
    })
    if err != nil {
        log.Fatal(err)
    }

    session.On(func(event copilot.SessionEvent) {
        switch d := event.Data.(type) {
        case *copilot.AssistantMessageDeltaData:
            fmt.Print(d.DeltaContent)
        case *copilot.SessionIdleData:
            _ = d
            fmt.Println()
        }
    })

    fmt.Println("🌤️  Weather Assistant (type 'exit' to quit)")
    fmt.Println("   Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\n")

    scanner := bufio.NewScanner(os.Stdin)
    for {
        fmt.Print("You: ")
        if !scanner.Scan() {
            break
        }
        input := scanner.Text()
        if strings.ToLower(input) == "exit" {
            break
        }

        fmt.Print("Assistant: ")
        _, err = session.SendAndWait(ctx, copilot.MessageOptions{Prompt: input})
        if err != nil {
            fmt.Fprintf(os.Stderr, "Error: %v\n", err)
            break
        }
        fmt.Println()
    }
    if err := scanner.Err(); err != nil {
        fmt.Fprintf(os.Stderr, "Input error: %v\n", err)
    }
}
```

次のコマンドを使用して実行します。

```bash
go run weather-assistant.go
```

</div>

<div class="ghd-codetab" data-lang="rust" data-label="Rust"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Rust</div>

`src/main.rs`を作成します。

```rust
use std::io::{self, BufRead, Write};
use std::sync::Arc;
use std::time::Duration;

use github_copilot_sdk::handler::ApproveAllHandler;
use github_copilot_sdk::tool::{JsonSchema, ToolHandlerRouter, define_tool};
use github_copilot_sdk::{Client, ClientOptions, MessageOptions, SessionConfig, ToolResult};
use serde::Deserialize;

#[derive(Deserialize, JsonSchema)]
struct GetWeatherParams {
    city: String,
}

fn read_line() -> Option<String> {
    let stdin = io::stdin();
    let mut line = String::new();
    stdin.lock().read_line(&mut line).ok()?;
    if line.is_empty() {
        return None;
    }
    Some(line.trim_end_matches(&['\n', '\r'][..]).to_string())
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let router = ToolHandlerRouter::new(
        vec![define_tool(
            "get_weather",
            "Get the current weather for a city",
            |_inv, params: GetWeatherParams| async move {
                Ok(ToolResult::Text(format!(
                    "{}: 62°F and sunny",
                    params.city
                )))
            },
        )],
        Arc::new(ApproveAllHandler),
    );
    let tools = router.tools();

    let client = Client::start(ClientOptions::default()).await?;

    let mut config = SessionConfig::default();
    config.streaming = Some(true);
    config.tools = Some(tools);
    let session = client.create_session(config.with_handler(Arc::new(router))).await?;

    let mut events = session.subscribe();
    tokio::spawn(async move {
        while let Ok(event) = events.recv().await {
            match event.event_type.as_str() {
                "assistant.message_delta" => {
                    if let Some(text) =
                        event.data.get("deltaContent").and_then(|value| value.as_str())
                    {
                        print!("{text}");
                        io::stdout().flush().ok();
                    }
                }
                "assistant.message" => println!(),
                _ => {}
            }
        }
    });

    println!("Weather Assistant (type 'exit' to quit)");
    println!("Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\n");

    loop {
        print!("You: ");
        io::stdout().flush().ok();

        let Some(input) = read_line() else { break };
        if input.eq_ignore_ascii_case("exit") {
            break;
        }

        print!("Assistant: ");
        io::stdout().flush().ok();
        session
            .send_and_wait(MessageOptions::new(input).with_wait_timeout(Duration::from_secs(120)))
            .await?;
        println!();
    }

    session.disconnect().await?;
    client.stop().await?;
    Ok(())
}
```

次のコマンドを使用して実行します。

```bash
cargo run
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

新しいコンソール プロジェクトを作成し、 `Program.cs`を更新します。

```csharp
using GitHub.Copilot;
using Microsoft.Extensions.AI;
using System.ComponentModel;

// Define the weather tool
var getWeather = CopilotTool.DefineTool(
    ([Description("The city name")] string city) =>
    {
        var conditions = new[] { "sunny", "cloudy", "rainy", "partly cloudy" };
        var temp = Random.Shared.Next(50, 80);
        var condition = conditions[Random.Shared.Next(conditions.Length)];
        return new { city, temperature = $"{temp}°F", condition };
    },
    factoryOptions: new AIFunctionFactoryOptions
    {
        Name = "get_weather",
        Description = "Get the current weather for a city",
    });

await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-4.1",
    OnPermissionRequest = PermissionHandler.ApproveAll,
    Streaming = true,
    Tools = [getWeather]
});

// Listen for response chunks
session.On<SessionEvent>(ev =>
{
    if (ev is AssistantMessageDeltaEvent deltaEvent)
    {
        Console.Write(deltaEvent.Data.DeltaContent);
    }
    if (ev is SessionIdleEvent)
    {
        Console.WriteLine();
    }
});

Console.WriteLine("🌤️  Weather Assistant (type 'exit' to quit)");
Console.WriteLine("   Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\n");

while (true)
{
    Console.Write("You: ");
    var input = Console.ReadLine();

    if (string.IsNullOrEmpty(input) || input.Equals("exit", StringComparison.OrdinalIgnoreCase))
    {
        break;
    }

    Console.Write("Assistant: ");
    await session.SendAndWaitAsync(new MessageOptions { Prompt = input });
    Console.WriteLine("\n");
}
```

次のコマンドを使用して実行します。

```bash
dotnet run
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

`WeatherAssistant.java`を作成します。

```java
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.events.*;
import com.github.copilot.sdk.json.*;

import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Scanner;
import java.util.concurrent.CompletableFuture;

public class WeatherAssistant {
    public static void main(String[] args) throws Exception {
        var random = new Random();
        var conditions = List.of("sunny", "cloudy", "rainy", "partly cloudy");

        var getWeather = ToolDefinition.create(
            "get_weather",
            "Get the current weather for a city",
            Map.of(
                "type", "object",
                "properties", Map.of(
                    "city", Map.of("type", "string", "description", "The city name")
                ),
                "required", List.of("city")
            ),
            invocation -> {
                var city = (String) invocation.getArguments().get("city");
                var temp = random.nextInt(30) + 50;
                var condition = conditions.get(random.nextInt(conditions.size()));
                return CompletableFuture.completedFuture(Map.of(
                    "city", city,
                    "temperature", temp + "°F",
                    "condition", condition
                ));
            }
        );

        try (var client = new CopilotClient()) {
            client.start().get();

            var session = client.createSession(
                new SessionConfig()
                    .setModel("gpt-4.1")
                    .setStreaming(true)
                    .setOnPermissionRequest(request ->
                        CompletableFuture.completedFuture(PermissionDecision.allow())
                    )
                    .setTools(List.of(getWeather))
            ).get();

            session.on(AssistantMessageDeltaEvent.class, delta -> {
                System.out.print(delta.getData().deltaContent());
            });
            session.on(SessionIdleEvent.class, idle -> {
                System.out.println();
            });

            System.out.println("🌤️  Weather Assistant (type 'exit' to quit)");
            System.out.println("   Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\n");

            var scanner = new Scanner(System.in);
            while (true) {
                System.out.print("You: ");
                if (!scanner.hasNextLine()) break;
                var input = scanner.nextLine();
                if (input.equalsIgnoreCase("exit")) break;

                System.out.print("Assistant: ");
                session.sendAndWait(
                    new MessageOptions().setPrompt(input)
                ).get();
                System.out.println("\n");
            }

            client.stop().get();
        }
    }
}
```

次のコマンドを使用して実行します。

```bash
javac -cp copilot-sdk.jar WeatherAssistant.java && java -cp .:copilot-sdk.jar WeatherAssistant
```

</div>

</div>

**セッションの例:**

```text
🌤️  Weather Assistant (type 'exit' to quit)
   Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'

You: What's the weather in Seattle?
Assistant: Let me check the weather for Seattle...
It's currently 62°F and cloudy in Seattle.

You: How about Tokyo and London?
Assistant: I'll check both cities for you:
- Tokyo: 75°F and sunny
- London: 58°F and rainy

You: exit
```

Copilot呼び出し可能なカスタム ツールを使用してアシスタントを構築しました。

## ツールのしくみ

ツールを定義するということは、Copilot に次のことを伝えていることになります:

1. **ツールの機能** (説明)
2. **必要なパラメーター** (スキーマ)
3. **実行するコード** (ハンドラー)

Copilotは、ユーザーの質問に基づいてツールを呼び出すタイミングを決定します。 その場合:

1. Copilot はパラメーターを使用してツール呼び出し要求を送信します
2. SDK によってハンドラー関数が実行されます
3. 結果はCopilotに送り返されます
4. Copilotは結果を応答に組み込みます

## 次は何ですか?

基本を理解したところで、さらに便利な機能をご紹介します:

### MCP サーバーに接続する

MCP (モデル コンテキスト プロトコル) サーバーには、事前構築済みのツールが用意されています。 GitHubの MCP サーバーに接続して、リポジトリ、問題、プル要求にCopilotアクセスできるようにします。

```typescript
const session = await client.createSession({
    mcpServers: {
        github: {
            type: "http",
            url: "https://api.githubcopilot.com/mcp/",
        },
    },
});
```

📖
\*\*
[GitHub Copilot SDK での MCP サーバーの使用](/ja/copilot/how-tos/copilot-sdk/features/mcp)\*\* - ローカル サーバーとリモート サーバー、すべての構成オプション、トラブルシューティングについて説明します。

### カスタム エージェントを作成する

特定のタスクに特化した AI ペルソナを定義します。

```typescript
const session = await client.createSession({
    customAgents: [{
        name: "pr-reviewer",
        displayName: "PR Reviewer",
        description: "Reviews pull requests for best practices",
        prompt: "You are an expert code reviewer. Focus on security, performance, and maintainability.",
    }],
});
```

> \[!TIP]
> セッション構成で `agent: "pr-reviewer"` を設定して、最初からこのエージェントを事前に選択することもできます。 詳細については、 [カスタム エージェントとサブエージェント オーケストレーション](/ja/copilot/how-tos/copilot-sdk/features/custom-agents#selecting-an-agent-at-session-creation) を参照してください。

### システム メッセージをカスタマイズする

指示を追加することで、AI の動作と個性を制御します。

```typescript
const session = await client.createSession({
    systemMessage: {
        content: "You are a helpful assistant for our engineering team. Always be concise.",
    },
});
```

より詳細な制御を行うには、 `mode: "customize"` を使用して、残りの部分を維持しながら、システム プロンプトの個々のセクションをオーバーライドします。

```typescript
const session = await client.createSession({
    systemMessage: {
        mode: "customize",
        sections: {
            tone: { action: "replace", content: "Respond in a warm, professional tone. Be thorough in explanations." },
            code_change_rules: { action: "remove" },
            guidelines: { action: "append", content: "\n* Always cite data sources" },
        },
        content: "Focus on financial analysis and reporting.",
    },
});
```

使用可能なセクション ID: `identity`、 `tone`、 `tool_efficiency`、 `environment_context`、 `code_change_rules`、 `guidelines`、 `safety`、 `tool_instructions`、 `custom_instructions`、 `runtime_instructions`、 `last_instructions`。

各オーバーライドでは、 `replace`、 `remove`、 `append`、 `prepend`の 4 つのアクションがサポートされます。 不明なセクション ID は適切に処理されます。コンテンツは追加の命令に追加され、警告が出力されます。不明なセクションの `remove` は無視されます。

<c0>TypeScript\</c0 の例については、言語固有の SDK READM を参照してください> <c1>Python</c1>、<c2>Go</c2>、<c3>Rust</c3>、<c4>Java</c4>、および <c5>C#</c5>。

## 外部 CLI サーバーへの接続

既定では、COPILOT CLI プロセス ライフサイクルが SDK によって自動的に管理され、必要に応じて CLI が開始および停止されます。 ただし、サーバー モードで CLI を個別に実行し、SDK に接続することもできます。 これは、次の場合に役立ちます。

* **デバッグ**: SDK の再起動の間に CLI を実行したままにしてログを検査する
* **リソース共有**: 複数の SDK クライアントが同じ CLI サーバーに接続できる
* **開発**: カスタム設定または別の環境で CLI を実行する

### サーバー モードでの CLI の実行

`--headless` フラグを使用してサーバー モードで CLI を起動し、必要に応じてポートを指定します。

```bash
copilot --headless --port 4321
```

ポートを指定しない場合、CLI はランダムに使用可能なポートを選択します。

既定では、ヘッドレス サーバーはループバック (`127.0.0.1`) からの接続のみを受け入れるため、SDK は同じコンピューター上で実行する必要があります。 他のホスト (コンテナーまたは別のサーバーで CLI を実行する場合など) からの接続を受け入れるには、 `--host`を使用して非ループバック アドレスにバインドします。

```bash
# Listen on all interfaces
copilot --headless --host 0.0.0.0 --port 4321
```

> \[!WARNING]
> 非ループバック アドレスでヘッドレス サーバーを公開すると、そのアドレスにルーティングできるすべてのユーザーがヘッドレス サーバーに到達できるようになります。 ネットワーク制御 (ファイアウォール、プライベート ネットワーク、リバース プロキシ) と、環境に適した認証と組み合わせてください。

### 外部サーバーへの SDK の接続

CLI がサーバー モードで実行されたら、"cli url" オプションを使用してそれに接続するように SDK クライアントを構成します。

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

```typescript
import { CopilotClient, approveAll } from "@github/copilot-sdk";

const client = new CopilotClient({
    cliUrl: "localhost:4321"
});

// Use the client normally
const session = await client.createSession({ onPermissionRequest: approveAll });
// ...
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

```python
from copilot import CopilotClient, RuntimeConnection
from copilot.session import PermissionHandler

client = CopilotClient(connection=RuntimeConnection.for_uri("localhost:4321"))
await client.start()

# Use the client normally
session = await client.create_session(on_permission_request=PermissionHandler.approve_all)
# ...
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

```golang
package main

import (
    "context"
    "log"

    copilot "github.com/github/copilot-sdk/go"
)

func main() {
    ctx := context.Background()

    client := copilot.NewClient(&copilot.ClientOptions{
        Connection: copilot.UriConnection{URL: "localhost:4321"},
    })

    if err := client.Start(ctx); err != nil {
        log.Fatal(err)
    }
    defer client.Stop()

    // Use the client normally
    _, _ = client.CreateSession(ctx, &copilot.SessionConfig{
        OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
    })
}
```

```golang
import copilot "github.com/github/copilot-sdk/go"

client := copilot.NewClient(&copilot.ClientOptions{
    Connection: copilot.UriConnection{URL: "localhost:4321"},
})

if err := client.Start(ctx); err != nil {
    log.Fatal(err)
}
defer client.Stop()

// Use the client normally
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
    OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
// ...
```

</div>

<div class="ghd-codetab" data-lang="rust" data-label="Rust"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Rust</div>

```rust
use std::sync::Arc;

use github_copilot_sdk::handler::ApproveAllHandler;
use github_copilot_sdk::{Client, ClientOptions, SessionConfig, Transport};

let mut options = ClientOptions::default();
options.transport = Transport::External {
    host: "localhost".to_string(),
    port: 4321,
};
let client = Client::start(options).await?;

// Use the client normally
let session = client
    .create_session(SessionConfig::default().with_handler(Arc::new(ApproveAllHandler)))
    .await?;
// ...
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

```csharp
using GitHub.Copilot;

using var client = new CopilotClient(new CopilotClientOptions
{
    Connection = RuntimeConnection.ForUri("localhost:4321"),
});

// Use the client normally
await using var session = await client.CreateSessionAsync(new()
{
    OnPermissionRequest = PermissionHandler.ApproveAll
});
// ...
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

```java
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.json.*;

var client = new CopilotClient(
    new CopilotClientOptions().setCliUrl("localhost:4321")
);
client.start().get();

// Use the client normally
var session = client.createSession(
    new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
// ...
```

</div>

</div>

**メモ：**`cli_url` / `cliUrl`/Go の`UriConnection`が提供されている場合、または Rust が`Transport::External`を使用している場合、SDK は CLI プロセスを生成または管理しません。指定された URL にある既存のサーバーにのみ接続されます。

## テレメトリと可観測性

Copilot SDK では、分散トレースの [OpenTelemetry](https://opentelemetry.io/) がサポートされています。 CLI プロセスからのトレース エクスポートと、SDK と CLI 間の `telemetry`の自動伝達を有効にする[](https://www.w3.org/TR/trace-context/)構成をクライアントに提供します。

### テレメトリの有効化

クライアントの作成時に `telemetry` (または `Telemetry`) 構成を渡します。 これはオプトインです。個別の "有効" フラグは必要ありません。

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

<!-- docs-validate: skip -->

```typescript
import { CopilotClient } from "@github/copilot-sdk";

const client = new CopilotClient({
  telemetry: {
    otlpEndpoint: "http://localhost:4318",
  },
});
```

オプションのピア依存関係: `@opentelemetry/api`

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

<!-- docs-validate: skip -->

```python
from copilot import CopilotClient, CopilotClientOptions

client = CopilotClient(CopilotClientOptions(
    telemetry={
        "otlp_endpoint": "http://localhost:4318",
    },
))
```

テレメトリの追加機能を使用してインストールする: `pip install copilot-sdk[telemetry]` ( `opentelemetry-api`を提供)

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

<!-- docs-validate: skip -->

```golang
client, err := copilot.NewClient(copilot.ClientOptions{
    Telemetry: &copilot.TelemetryConfig{
        OTLPEndpoint: "http://localhost:4318",
    },
})
```

依存 関係： `go.opentelemetry.io/otel`

</div>

<div class="ghd-codetab" data-lang="rust" data-label="Rust"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Rust</div>

<!-- docs-validate: skip -->

```rust
use github_copilot_sdk::{Client, ClientOptions, OtelExporterType, TelemetryConfig};

let mut options = ClientOptions::default();
options.telemetry = Some(
    TelemetryConfig::new()
        .with_exporter_type(OtelExporterType::OtlpHttp)
        .with_otlp_endpoint("http://localhost:4318"),
);
let client = Client::start(options).await?;
```

追加の依存関係はありません。SDK は、生成された CLI プロセス用のテレメトリ環境変数を挿入します。

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

<!-- docs-validate: skip -->

```csharp
var client = new CopilotClient(new CopilotClientOptions
{
    Telemetry = new TelemetryConfig
    {
        OtlpEndpoint = "http://localhost:4318",
    },
});
```

追加の依存関係はありません。組み込みの `System.Diagnostics.Activity`を使用します。

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

<!-- docs-validate: skip -->

```java
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.json.*;

var client = new CopilotClient(new CopilotClientOptions()
    .setTelemetry(new TelemetryConfig()
        .setOtlpEndpoint("http://localhost:4318")));
```

依存 関係： `io.opentelemetry:opentelemetry-api`

</div>

</div>

### TelemetryConfig オプション

| オプション                      | Node.js          | Python            | Go               | Rust              | Java             | .NET             | Description           |
| -------------------------- | ---------------- | ----------------- | ---------------- | ----------------- | ---------------- | ---------------- | --------------------- |
| OTLP エンドポイント               | `otlpEndpoint`   | `otlp_endpoint`   | `OTLPEndpoint`   | `otlp_endpoint`   | `otlpEndpoint`   | `OtlpEndpoint`   | OTLP HTTP エンドポイント URL |
| ファイルパス                     | `filePath`       | `file_path`       | `FilePath`       | `file_path`       | `filePath`       | `FilePath`       | JSON 行トレース出力のファイル パス  |
| エクスポーターの種類                 | `exporterType`   | `exporter_type`   | `ExporterType`   | `exporter_type`   | `exporterType`   | `ExporterType`   |                       |
| `"otlp-http"` または `"file"` |                  |                   |                  |                   |                  |                  |                       |
| 求人者名                       | `sourceName`     | `source_name`     | `SourceName`     | `source_name`     | `sourceName`     | `SourceName`     | 計装範囲名                 |
| コンテンツをキャプチャする              | `captureContent` | `capture_content` | `CaptureContent` | `capture_content` | `captureContent` | `CaptureContent` | メッセージの内容をキャプチャするかどうか  |

### ファイルのエクスポート

OTLP エンドポイントの代わりにローカル ファイルにトレースを書き込むには、

<!-- docs-validate: skip -->

```typescript
const client = new CopilotClient({
  telemetry: {
    filePath: "./traces.jsonl",
    exporterType: "file",
  },
});
```

### トレース コンテキストの伝達

トレース コンテキストは自動的に伝達されます。手動によるインストルメンテーションは必要ありません。

* **SDK → CLI**: 現在のスパン/アクティビティの `traceparent` ヘッダーと `tracestate` ヘッダーは、`session.create`、`session.resume`、および `session.send` RPC 呼び出しに含まれます。
* **CLI → SDK**: CLI がツール ハンドラーを呼び出すと、CLI のスパンからのトレース コンテキストが伝達され、ツール コードが正しい親スパンで実行されます。

📖
\*\*
[Copilot SDK 用の OpenTelemetry インストルメンテーション](/ja/copilot/how-tos/copilot-sdk/observability/opentelemetry)\*\* - TelemetryConfig オプション、トレース コンテキスト伝達、および言語ごとの依存関係。

## 詳細情報

* [認証](/ja/copilot/how-tos/copilot-sdk/auth/authenticate) - GitHub OAuth、環境変数、BYOK
* [BYOK (独自のキーを持ち込む)](/ja/copilot/how-tos/copilot-sdk/auth/byok) - Azure AI Foundry、OpenAI などの独自の API キーを使用します。
* [Node.js SDK リファレンス](https://github.com/github/copilot-sdk/tree/main/nodejs/README.md)
* [Python SDK リファレンス](https://github.com/github/copilot-sdk/tree/main/python/README.md)
* [Go SDK リファレンス](https://github.com/github/copilot-sdk/tree/main/go/README.md)
* [Rust SDK リファレンス](https://github.com/github/copilot-sdk/tree/main/rust/README.md)
* [.NET SDK リファレンス](https://github.com/github/copilot-sdk/tree/main/dotnet/README.md)
* [Java SDK リファレンス](https://github.com/github/copilot-sdk/tree/main/java/README.md)
* [GitHub Copilot SDK での MCP サーバーの使用](/ja/copilot/how-tos/copilot-sdk/features/mcp) - モデル コンテキスト プロトコルを使用して外部ツールを統合する
* [GitHub MCP サーバーのドキュメント](https://github.com/github/github-mcp-server)
* [MCP サーバー ディレクトリ](https://github.com/modelcontextprotocol/servers) - MCP サーバーの詳細を確認する
* [Copilot SDK 用の OpenTelemetry インストルメンテーション](/ja/copilot/how-tos/copilot-sdk/observability/opentelemetry) - TelemetryConfig、トレース コンテキストの伝達、言語ごとの依存関係

**それをやりました！** GitHub Copilot SDK の主要な概念を学習しました。

* ✅ クライアントとセッションの作成
* ✅ メッセージの送信と応答の受信
* ✅ リアルタイム出力のためのストリーミング
* ✅ Copilot が呼び出せるカスタム ツールを定義する

今、素晴らしい何かを構築に行く!
🚀