# Crea tu primera aplicación con tecnología Copilot

En este tutorial, usará el SDK de Copilot para compilar un asistente de línea de comandos. Empezarás con los conceptos básicos, añadirás respuestas en tiempo real y, a continuación, añadirás herramientas personalizadas, lo que le dará a Copilot la capacidad de invocar tu código.

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

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

**Lo que vas a construir:**

```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

Antes de comenzar, asegúrese de que tiene:

* **GitHub Copilot CLI** instalada y autenticada (los SDK de Node.js, Python y .NET proporcionan automáticamente la CLI; consulte [Configuración predeterminada (CLI agrupada)](/es/copilot/how-tos/copilot-sdk/setup/bundled-cli). Necesario para Go, Java y Rust, a menos que usen sus funciones de empaquetado de la CLI a nivel de aplicación).
* Su entorno de ejecución de lenguaje preferido:
  * **Node.js** 20+ o **Python** 3.11+ o **Go** 1.24+ o **Rust** 1.94+ o **Java** 17+ o **.NET** 8.0+

Compruebe que la CLI funciona:

```bash
copilot --version
```

## Paso 1: instalar el 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>

En primer lugar, cree un nuevo directorio e inicialice el proyecto:

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

A continuación, instale el SDK y el ejecutor de 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>

En primer lugar, cree un nuevo directorio e inicialice el módulo:

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

A continuación, instale el 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>

En primer lugar, cree una nueva caja binaria:

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

A continuación, instale el SDK y las dependencias directas usadas por los ejemplos:

```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>

En primer lugar, cree un proyecto de consola:

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

A continuación, agregue el 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>

En primer lugar, cree un nuevo directorio e inicialice el proyecto.

**Maven**: añade a tu `pom.xml`

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

**Gradle**—añadir a tu `build.gradle`:

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

</div>

</div>

## Paso 2: enviar el primer mensaje

Cree un nuevo archivo y agregue el código siguiente. Esta es la manera más sencilla de usar el SDK, aproximadamente 5 líneas de código.

<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>

Creación de `index.ts`:

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

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

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

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

Ejecútelo:

```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>

Creación de `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="auto")
    response = await session.send_and_wait("What is 2 + 2?")
    print(response.data.content)

    await client.stop()

asyncio.run(main())
```

Ejecútelo:

```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>

Creación de `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: "auto"})
    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)
}
```

Ejecútelo:

```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>

Creación de `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_permission_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(())
}
```

Ejecútelo:

```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>

Cree un nuevo proyecto de consola y agréguelo a `Program.cs`:

```csharp
using GitHub.Copilot;

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

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

Ejecútelo:

```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>

Creación de `HelloCopilot.java`:

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

```java
import com.github.copilot.CopilotClient;
import com.github.copilot.rpc.*;

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("auto")
                    .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();
        }
    }
}
```

Ejecútelo:

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

</div>

</div>

**Debería ver:**

```text
4
```

¡Felicidades! Acaba de crear su primera aplicación con tecnología Copilot.

## Paso 3: agregar respuestas de streaming

Ahora mismo, tienes que esperar a que se muestre la respuesta completa antes de ver nada. Vamos a hacer que sea interactivo mediante el streaming de la respuesta a medida que se genera.

<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>

Actualizar `index.ts`:

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

const client = new CopilotClient();
const session = await client.createSession({
    model: "auto",
    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>

Actualizar `main.py`:

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

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

    session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model="auto", 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>

Actualizar `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:     "auto",
        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>

Actualizar `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_permission_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>

Actualizar `Program.cs`:

```csharp
using GitHub.Copilot;

await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "auto",
    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>

Actualizar `HelloCopilot.java`:

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

```java
import com.github.copilot.CopilotClient;
import com.github.copilot.rpc.*;

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("auto")
                    .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>

Vuelva a ejecutar el código. Verá que la respuesta aparece palabra por palabra.

### Métodos de suscripción de eventos

El SDK proporciona métodos para suscribirse a eventos de sesión:

| Método                   | Description                                                                                                             |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------- |
| `on(handler)`            | Suscribirse a todos los eventos; devuelve la función de cancelación de suscripción                                      |
| `on(eventType, handler)` | Suscribirse a un tipo específico de evento (solo Node.js/TypeScript); devuelve una función para cancelar la suscripción |
| `subscribe()`            | Suscribirse a todos los eventos (Rust); filtrar por `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
# 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
// 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
// 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>

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

```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>

## Paso 4: agregar una herramienta personalizada

Y ahora viene la parte potente. Vamos a darle a Copilot la capacidad de llamar a tu código definiendo una herramienta personalizada. Crearemos una herramienta de búsqueda meteorológica sencilla.

<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>

Actualizar `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: "auto",
    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>

Actualizar `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.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="auto", 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>

Actualizar `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:     "auto",
        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>

Actualizar `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::{define_tool, JsonSchema};
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 tools = 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
            )))
        },
    )];

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

    let mut config = SessionConfig::default();
    config.streaming = Some(true);
    let session = client
        .create_session(
            config
                .with_tools(tools)
                .with_permission_handler(Arc::new(ApproveAllHandler)),
        )
        .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>

Actualizar `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 = "auto",
    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>

Actualizar `HelloCopilot.java`:

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

```java
import com.github.copilot.CopilotClient;
import com.github.copilot.rpc.*;

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("auto")
                    .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>

Ejecútelo y verá que Copilot usa la herramienta para obtener datos del tiempo y, a continuación, responde con los resultados.

## Paso 5: crear un asistente interactivo

Vamos a ponerlo todo juntos en un asistente interactivo útil:

<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: "auto",
    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();
```

Ejecute con:

```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>

Creación de `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.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="auto", 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())
```

Ejecute con:

```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>

Creación de `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:     "auto",
        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)
    }
}
```

Ejecute con:

```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>

Creación de `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::{define_tool, JsonSchema};
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 tools = 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
            )))
        },
    )];

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

    let mut config = SessionConfig::default();
    config.streaming = Some(true);
    let session = client
        .create_session(
            config
                .with_tools(tools)
                .with_permission_handler(Arc::new(ApproveAllHandler)),
        )
        .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(())
}
```

Ejecute con:

```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>

Cree un nuevo proyecto de consola y actualice `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 = "auto",
    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");
}
```

Ejecute con:

```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>

Creación de `WeatherAssistant.java`:

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

```java
import com.github.copilot.CopilotClient;
import com.github.copilot.rpc.*;

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("auto")
                    .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();
        }
    }
}
```

Ejecute con:

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

</div>

</div>

**Sesión de ejemplo:**

```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
```

¡Has creado un asistente con una herramienta personalizada que Copilot puede invocar!

## Funcionamiento de las herramientas

Cuando defines una herramienta, le estás diciendo a Copilot:

1. **Qué hace la herramienta** (descripción)
2. **Qué parámetros necesita** (esquema)
3. **Qué código se va a ejecutar** (controlador)

Copilot decide cuándo llamar a la herramienta en función de la pregunta del usuario. Cuando lo haga:

1. Copilot envía una solicitud de llamada de herramienta con los parámetros
2. El SDK ejecuta la función del controlador.
3. El resultado se devuelve a Copilot
4. Copilot incorpora el resultado en su respuesta

## ¿Qué sigue?

Ahora que tiene los conceptos básicos, estas son características más eficaces para explorar:

### Conexión a servidores MCP

Los servidores MCP (Protocolo de contexto de modelo) proporcionan herramientas pregeneradas. Conéctese al servidor MCP de GitHub para conceder a Copilot acceso a repositorios, problemas y solicitudes de incorporación de cambios:

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

📖
\*\*
[Uso de servidores MCP con el SDK de GitHub Copilot](/es/copilot/how-tos/copilot-sdk/features/mcp)\*\* : obtenga información sobre servidores locales frente a remotos, todas las opciones de configuración y la solución de problemas.

### Creación de agentes personalizados

Defina roles de IA especializados para tareas específicas:

```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]
> También puede establecer `agent: "pr-reviewer"` en la configuración de sesión para seleccionar previamente este agente desde el principio. Consulte [autotitle](/es/copilot/how-tos/copilot-sdk/features/custom-agents#selecting-an-agent-at-session-creation) para obtener más información.

### Personalización del mensaje del sistema

Controle el comportamiento y la personalidad de la inteligencia artificial anexando instrucciones:

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

Para un control más detallado, use `mode: "customize"` para anular secciones individuales del prompt del sistema sin dejar de preservar el resto:

```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.",
    },
});
```

Identificadores de sección disponibles: `preamble`, `identity`, `tone`, `tool_efficiency`, `code_change_rules`, `guidelines`, `environment_context`, `safety`, `tool_instructions`, `custom_instructions`, `last_instructions`, `runtime_instructions`.

`identity` y `tool_instructions` son *grupos* de secciones: tienen como destino una colección de subsecciones relacionadas como una unidad. Utilice `preamble` para apuntar solo al preámbulo de la identidad sin afectar a sus subsecciones hermanas.

Cada anulación admite cinco acciones: `replace`, `remove`, `append`, `prepend`, y `preserve`. La acción `preserve` es una operación nula que excluye una sección direccionable individualmente de un `remove` en un grupo (por ejemplo, mantener `tone` al eliminar el grupo `identity`). Los identificadores de sección desconocidos se gestionan correctamente: el contenido de las anulaciones de `replace`/`append`/`prepend` se añade a las instrucciones adicionales, y las anulaciones de `remove` se omiten silenciosamente.

Consulte los READMEs del SDK específicos del lenguaje para obtener ejemplos en [TypeScript](https://github.com/github/copilot-sdk/tree/main/nodejs/README.md), [Python](https://github.com/github/copilot-sdk/tree/main/python/README.md), [Go](https://github.com/github/copilot-sdk/tree/main/go/README.md), [Rust](https://github.com/github/copilot-sdk/tree/main/rust/README.md), [Java](https://github.com/github/copilot-sdk/tree/main/java/README.md) y [C#](https://github.com/github/copilot-sdk/tree/main/dotnet/README.md).

## Conexión a un servidor de la CLI externo

De forma predeterminada, el SDK administra automáticamente el ciclo de vida del proceso de la CLI de Copilot, iniciando y deteniendo la CLI según sea necesario. Sin embargo, también puede ejecutar la CLI en modo de servidor por separado y hacer que el SDK se conecte a él. Esto puede ser útil para:

* **Depuración**: Mantenga la interfaz de línea de comandos en ejecución entre reinicios del SDK para inspeccionar los registros
* **Uso compartido de recursos**: varios clientes del SDK pueden conectarse al mismo servidor de la CLI
* **Desarrollo**: ejecute la CLI con la configuración personalizada o en un entorno diferente.

### Ejecución de la CLI en modo de servidor

Inicie la CLI en modo de servidor con la `--headless` marca y, opcionalmente, especifique un puerto:

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

Si no especifica un puerto, la CLI elegirá un puerto disponible aleatoriamente.

De forma predeterminada, el servidor headless solo acepta conexiones de loopback (`127.0.0.1`), por lo que el SDK debe ejecutarse en la misma máquina. Para aceptar conexiones desde otros hosts (por ejemplo, al ejecutar la CLI en un contenedor o en un servidor independiente), vincúlelo a una dirección distinta de la de loopback con `--host`:

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

> \[!WARNING]
> Exponer el servidor sin encabezado en una dirección que no sea de bucle invertido hace que sea accesible por cualquier persona que pueda enrutar a esa dirección. Complételo con controles de red (cortafuegos, una red privada, proxy inverso) y mecanismos de autenticación adecuados para su entorno.

### Conexión del SDK al servidor externo

Una vez que la CLI se ejecuta en modo de servidor, configure el cliente del SDK para conectarse a él mediante la opción "cli url":

<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
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,
    connection_token: None,
};
let client = Client::start(options).await?;

// Use the client normally
let session = client
    .create_session(SessionConfig::default().with_permission_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.CopilotClient;
import com.github.copilot.rpc.*;

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>

**Nota:** Cuando se proporciona `cli_url` / `cliUrl` o el `URIConnection` de Go, o Rust usa `Transport::External`, el SDK no iniciará ni administrará un proceso de CLI; solo se conectará al servidor existente en la URL especificada.

## Telemetría y observabilidad

El SDK de Copilot admite [OpenTelemetry](https://opentelemetry.io/) para el seguimiento distribuido. Proporcione una `telemetry` configuración al cliente para habilitar la exportación de seguimiento desde el proceso de la CLI y la propagación automática del [contexto de seguimiento de W3C](https://www.w3.org/TR/trace-context/) entre el SDK y la CLI.

### Habilitación de telemetría

Pasa una configuración `telemetry` (o `Telemetry`) al crear el cliente. Esta es la opción de aceptación voluntaria; no se necesita ningún indicador de «habilitado» por separado.

<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",
  },
});
```

Dependencia de par opcional: `@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",
    },
))
```

Instalación con extras de telemetría: `pip install copilot-sdk[telemetry]` (proporciona `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 := copilot.NewClient(&copilot.ClientOptions{
    Telemetry: &copilot.TelemetryConfig{
        OTLPEndpoint: "http://localhost:4318",
    },
})
```

Dependencia: `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?;
```

Sin dependencias adicionales: el SDK inserta variables de entorno de telemetría para el proceso de la CLI generado.

</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",
    },
});
```

Sin dependencias adicionales: usa `System.Diagnostics.Activity` integrado.

</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.CopilotClient;
import com.github.copilot.rpc.*;

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

Dependencia: `io.opentelemetry:opentelemetry-api`

</div>

</div>

### Opciones de TelemetryConfig

| Opción                    | Node.js          | Python            | Ir               | Óxido             | Java             | .NET             | Description                                                                      |
| ------------------------- | ---------------- | ----------------- | ---------------- | ----------------- | ---------------- | ---------------- | -------------------------------------------------------------------------------- |
| Punto de conexión de OTLP | `otlpEndpoint`   | `otlp_endpoint`   | `OTLPEndpoint`   | `otlp_endpoint`   | `otlpEndpoint`   | `OtlpEndpoint`   | Dirección URL del punto de conexión HTTP de OTLP                                 |
| Protocolo OTLP            | `otlpProtocol`   | `otlp_protocol`   | `OTLPProtocol`   | `otlp_protocol`   | `otlpProtocol`   | `OtlpProtocol`   | Protocolo HTTP de OTLP para todas las señales: `"http/json"` o `"http/protobuf"` |
| Ruta del archivo          | `filePath`       | `file_path`       | `FilePath`       | `file_path`       | `filePath`       | `FilePath`       | Ruta de acceso de archivo para salida de seguimiento de líneas JSON              |
| Tipo de exportador        | `exporterType`   | `exporter_type`   | `ExporterType`   | `exporter_type`   | `exporterType`   | `ExporterType`   |                                                                                  |
| `"otlp-http"` o `"file"`  |                  |                   |                  |                   |                  |                  |                                                                                  |
| Nombre de origen          | `sourceName`     | `source_name`     | `SourceName`     | `source_name`     | `sourceName`     | `SourceName`     | Nombre del ámbito de instrumentación                                             |
| Captura de contenido      | `captureContent` | `capture_content` | `CaptureContent` | `capture_content` | `captureContent` | `CaptureContent` | Si se va a capturar el contenido del mensaje                                     |

El campo de protocolo OTLP configura el exportador `"otlp-http"` de la CLI para todas las señales. Déjelo sin definir para usar el valor predeterminado de la CLI, o configúrelo como `"http/protobuf"` para exportar en formato protobuf a través de HTTP.

### Exportación de archivos

Para escribir las trazas en un archivo local en lugar de en un punto de conexión OTLP:

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

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

### Propagación del contexto de rastreo

El contexto de seguimiento se propaga automáticamente; no se necesita instrumentación manual:

* **SDK → CLI**: los encabezados `traceparent` y `tracestate` del span o la actividad actuales se incluyen en las llamadas RPC `session.create`, `session.resume` y `session.send`.
* **CLI → SDK**: cuando la CLI invoca controladores de herramientas, el contexto de seguimiento del intervalo de la CLI se propaga para que el código de la herramienta se ejecute bajo el intervalo primario correcto.

📖
\*\*
[Instrumentación de OpenTelemetry para el SDK de Copilot](/es/copilot/how-tos/copilot-sdk/observability/opentelemetry)\*\*: opciones de TelemetryConfig, propagación de contexto de seguimiento y dependencias por lenguaje.

## Aprende más

* [Autenticación](/es/copilot/how-tos/copilot-sdk/auth/authenticate): GitHub OAuth, variables de entorno y BYOK
* [BYOK (traiga su propia clave)](/es/copilot/how-tos/copilot-sdk/auth/byok) - Usa tus propias claves de API de Microsoft Foundry, OpenAI, etc.
* [ Referencia del SDK deNode.js](https://github.com/github/copilot-sdk/tree/main/nodejs/README.md)
* Referencia del SDK de [Python](https://github.com/github/copilot-sdk/tree/main/python/README.md)
* [Referencia del SDK de Go](https://github.com/github/copilot-sdk/tree/main/go/README.md)
* [Referencia del SDK de Rust](https://github.com/github/copilot-sdk/tree/main/rust/README.md)
* [Referencia del SDK de .NET](https://github.com/github/copilot-sdk/tree/main/dotnet/README.md)
* Referencia del SDK de [Java](https://github.com/github/copilot-sdk/tree/main/java/README.md)
* [Uso de servidores MCP con el SDK de GitHub Copilot](/es/copilot/how-tos/copilot-sdk/features/mcp) : integración de herramientas externas mediante el protocolo de contexto de modelo
* [GitHub documentación del servidor MCP](https://github.com/github/github-mcp-server)
* [Directorio de servidores MCP](https://github.com/modelcontextprotocol/servers) : exploración de más servidores MCP
* [Instrumentación de OpenTelemetry para el SDK de Copilot](/es/copilot/how-tos/copilot-sdk/observability/opentelemetry) - TelemetryConfig, propagación del contexto de seguimiento y dependencias específicas de cada lenguaje

**¡Lo hiciste!** Ha aprendido los conceptos básicos del SDK de GitHub Copilot:

* ✅ Creación de un cliente y una sesión
* ✅ Envío de mensajes y recepción de respuestas
* ✅ Transmisión de resultados en tiempo real
* ✅ Definir herramientas personalizadas que Copilot puede invocar

¡Ahora vamos a construir algo increíble!
🚀