К основному содержанию
правило официальный · GitHub

copilot-sdk-java — правило для GitHub Copilot: Java-клиент SDK

Правило подсказывает Copilot, как писать Java-приложения на GitHub Copilot SDK: инициализация клиента, сессии, асинхронные вызовы.

Установить в GitHub Copilot · Вручную: положить файлы Все способы и платформы ↓
.github/instructions/copilot-sdk-java.instructions.md
Открыть на GitHub

Что делает copilot-sdk-java

Это файл инструкций, который Copilot подхватывает при работе с *.java и pom.xml. Внутри — готовые шаблоны кода: создание CopilotClient через try-with-resources, настройка CopilotClientOptions, запуск и остановка сервера вручную, создание и возобновление сессий через SessionConfig и ResumeSessionConfig.

Отдельный блок посвящён виртуальным потокам. Автор правила прямо советует JDK 25 для продакшена: ошибки производительности виртуальных потоков починили только там, хотя сами потоки появились в JDK 21. Базово хватает Java 17, но часть примеров требует JDK 21 и выше. Ещё нужно, чтобы GitHub Copilot CLI стоял в PATH — без него клиент не запустится.

Все асинхронные операции возвращают CompletableFuture, а геттеры конфигураций отдают Optional<T>, чтобы отличать «не задано» от явного значения. SDK в публичном превью, так что ломающие изменения возможны. Для сессии обязателен обработчик разрешений onPermissionRequest — без него сессию не создать.

Какие задачи решает

  • собрать Java-клиент к Copilot SDK без чтения исходников
  • настроить виртуальные потоки для асинхронных вызовов
  • отличить незаданное значение конфигурации от явного
  • создать сессию с нужным набором инструментов и моделью
  • корректно освободить ресурсы клиента через try-with-resources

Примеры запросов агенту

  • Создай CopilotClient с логом уровня debug и запусти его
  • Настрой сессию с моделью gpt-5 и стримингом, обработчик разрешений — APPROVE_ALL
  • Переключи сессию на другую модель с reasoningEffort high

Как установить copilot-sdk-java

Вручную: положить файлы

.github/instructions/copilot-sdk-java.instructions.md

Поле applyTo задаёт, к каким файлам применять

По шагам, с командами для каждой платформы: AGENTS.md и CLAUDE.md: что это, кто читает и какой выбрать

Из того же набора732

Весь набор →
cpp-language-service-tools Правило направляет GitHub Copilot к инструментам IntelliSense для поиска определений, ссылок и связей вызовов в C++. Пригодится при рефакторинге и изменении сигнатур. ★ 40 418звёзд репо copilot-thought-logging Правило заставляет Copilot вести файл Copilot-Processing.md с планом и отметками о выполнении, чтобы вы видели ход работы и могли его поправить. ★ 40 418звёзд репо copilot-sdk-python Инструкция для GitHub Copilot по разработке Python-приложений на базе github-copilot-sdk. Помогает писать асинхронный код сессий, регистрировать инструменты и обрабатывать стриминг. ★ 40 418звёзд репо copilot-sdk-nodejs Правило задаёт паттерны для Node.js и TypeScript-приложений на GitHub Copilot SDK: от запуска клиента до сессий и событий. ★ 40 418звёзд репо copilot-sdk-go Инструкции для ИИ-ассистента по разработке приложений на Go с библиотекой Copilot SDK. Помогает писать интеграции, настраивать сессии и слушать события через каналы. ★ 40 418звёзд репо copilot-sdk-csharp Правило задаёт рекомендации для C#-проектов, использующих GitHub Copilot SDK. Оно пригодится при настройке клиента, сессий, событий и потоковых ответов. ★ 40 418звёзд репо convert-jpa-to-spring-data-cosmos Пошаговое правило для Copilot: переводит Spring Boot проект с JPA на Azure Cosmos DB через Spring Data Cosmos. Пригодится, когда миграция уже решена и нужен план. ★ 40 418звёзд репо convert-cassandra-to-spring-data-cosmos Инструкция для миграции проектов на Spring Boot с Apache Cassandra на Azure Cosmos DB через spring-data-cosmos. Применяется к коду, сборкам Maven или Gradle и файлам настроек. ★ 40 418звёзд репо

Похожие

aws-sdk-java-v2-lambda giuseppe-trisciuoglio Скилл подсказывает агенту, как вызывать и обновлять функции AWS Lambda через AWS SDK for Java 2.x. Пригодится, если пишешь на Java и работаешь с Lambda. CX Codex +1 3 700установок java-21 diegnghrmr Подсказывает агенту, как писать код на Java 21: records, sealed-типы, виртуальные потоки. Пригодится, когда проект уже перешёл на 21-ю версию. CX Codex +1 326установок aws-sdk-java-v2-bedrock giuseppe-trisciuoglio Скилл подсказывает агенту, как вызывать модели Amazon Bedrock через AWS SDK for Java 2.x: текст, картинки, эмбеддинги и стриминг. CX Codex +1 3 700установок catalyst-sdk catalystbyzoho Скилл подсказывает агенту, как инициализировать Catalyst SDK и обращаться к сервисам на Node.js, Python, Java, в браузере и на мобильных. CX Codex +1 1 000установок agentica-sdk parcadei Справочник по Agentica SDK: декоратор @agentic, spawn(), состояние агента, лимиты токенов и подключение MCP-серверов. CX Codex +1 472установок azure-monitor-ingestion-java Microsoft Подсказывает агенту, как отправлять кастомные логи в Azure Monitor через Logs Ingestion API, DCR и DCE на Java. ★ 3 148звёзд репо

Рядом в теме «Языки программирования»

Все правила IDE по теме «Языки программирования» →

Вопросы о copilot-sdk-java

Как установить copilot-sdk-java в GitHub Copilot?

Положите файл по пути .github/instructions/copilot-sdk-java.instructions.md — Copilot подхватит его для файлов *.java и pom.xml.

Что делает copilot-sdk-java?

Даёт Copilot готовые примеры работы с GitHub Copilot SDK для Java: инициализацию клиента, конфигурацию, сессии и операции с сообщениями.

Какая версия Java нужна?

Базово Java 17, часть примеров требует JDK 21. Для виртуальных потоков в продакшене правило советует JDK 25. Ещё нужен GitHub Copilot CLI в PATH.

Исходный текст

copilot-sdk-java.instructions.md · MIT
---
applyTo: '**/*.java, **/pom.xml'
description: 'This file provides guidance on building Java applications using GitHub Copilot SDK for Java.'
name: 'GitHub Copilot SDK Java Instructions'
---

## Core Principles

- The SDK is in public preview and may have breaking changes
- Requires Java 17 or later for baseline SDK usage. Some examples use newer JDK features and therefore require JDK 21 or later (for example, virtual threads via `Executors.newVirtualThreadPerTaskExecutor()` and `switch` pattern matching). **Java 25 or later highly recommended**.
- Requires GitHub Copilot CLI installed and in PATH
- Uses `CompletableFuture` for all async operations
- Implements `AutoCloseable` for resource cleanup (try-with-resources)
- Getters on configuration classes return `Optional<T>` (or `OptionalInt`/`OptionalDouble`) to distinguish "not set" from explicit values; setters accept raw types and return `this` for chaining. Use the `clear` methods to unset values if needed.

## Installation

### Maven

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

### Gradle

```groovy
implementation "com.github:copilot-sdk-java:${copilotSdkJavaVersion}"
```

## Client Initialization

### Basic Client Setup

```java
try (var client = new CopilotClient()) {
    client.start().get();
    // Use client...
}
```

### Virtual Threads (JDK 25+)

Virtual threads were introduced in JDK 21, but significant performance bugs were not fixed until JDK 25, making JDK 25 the minimum recommended version for production use of virtual threads. On JDK 25+, use a virtual-thread executor for significantly better scalability. The SDK's async operations will run on virtual threads instead of the default `ForkJoinPool`:

```java
var options = new CopilotClientOptions()
    .setExecutor(Executors.newVirtualThreadPerTaskExecutor());

try (var client = new CopilotClient(options)) {
    client.start().get();
    // Use client...
}
```

### Client Configuration Options

When creating a CopilotClient, use `CopilotClientOptions`:

- `cliPath` - Path to CLI executable (default: "copilot" from PATH)
- `cliArgs` - Extra arguments prepended before SDK-managed flags
- `cliUrl` - URL of existing CLI server (e.g., "localhost:8080"). When provided, client won't spawn a process
- `port` - Server port (default: 0 for random, only when `useStdio` is false)
- `useStdio` - Use stdio transport instead of TCP (default: true)
- `logLevel` - Log level: "error", "warn", "info", "debug", "trace" (default: "info")
- `autoStart` - Auto-start server on first request (default: true)
- `autoRestart` - Auto-restart on crash (default: true)
- `cwd` - Working directory for the CLI process
- `environment` - Environment variables for the CLI process
- `gitHubToken` - GitHub token for authentication
- `useLoggedInUser` - Use logged-in `gh` CLI auth (default: true unless token provided)
- `onListModels` - Custom model list handler for BYOK scenarios
- `remote` - Enable Mission Control / cloud session integration (default: false)
- `telemetry` - `TelemetryConfig` for OpenTelemetry export (since 1.2.0)
- `sessionIdleTimeoutSeconds` - Idle timeout before session auto-closes (since 1.3.0)
- `executor` - Custom `Executor` for async operations (default: ForkJoinPool)
- `tcpConnectionToken` - Security token for TCP transport authentication

```java
var options = new CopilotClientOptions()
    .setCliPath("/path/to/copilot")
    .setLogLevel("debug")
    .setAutoStart(true)
    .setAutoRestart(true)
    .setGitHubToken(System.getenv("GITHUB_TOKEN"));

try (var client = new CopilotClient(options)) {
    client.start().get();
    // Use client...
}
```

### Manual Server Control

For explicit control:
```java
var client = new CopilotClient(new CopilotClientOptions().setAutoStart(false));
client.start().get();
// Use client...
client.stop().get();
```

Use `forceStop()` when `stop()` takes too long.

## Session Management

### Creating Sessions

Use `SessionConfig` for configuration. The permission handler is **required**:

```java
var session = client.createSession(new SessionConfig()
    .setModel("gpt-5")
    .setStreaming(true)
    .setTools(List.of(...))
    .setSystemMessage(new SystemMessageConfig()
        .setMode(SystemMessageMode.APPEND)
        .setContent("Custom instructions"))
    .setAvailableTools(List.of("tool1", "tool2"))
    .setExcludedTools(List.of("tool3"))
    .setProvider(new ProviderConfig().setType("openai"))
    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
```

### Session Config Options

- `sessionId` - Custom session ID
- `clientName` - Application name
- `model` - Model name ("gpt-5", "claude-sonnet-4.5", etc.)
- `reasoningEffort` - "low", "medium", "high", "xhigh"
- `tools` - Custom tools exposed to the CLI
- `systemMessage` - System message customization
- `availableTools` - Allowlist of tool names
- `excludedTools` - Blocklist of tool names
- `provider` - Custom API provider configuration (BYOK)
- `streaming` - Enable streaming response chunks (default: false)
- `workingDirectory` - Session working directory
- `mcpServers` - MCP server configurations
- `customAgents` - Custom agent configurations
- `agent` - Pre-select agent by name
- `infiniteSessions` - Infinite sessions configuration
- `skillDirectories` - Skill SKILL.md directories
- `disabledSkills` - Skills to disable
- `configDir` - Config directory path
- `hooks` - Session lifecycle hooks
- `onPermissionRequest` - **REQUIRED** permission handler
- `onUserInputRequest` - User input handler
- `onEvent` - Event handler registered before session creation

All setters return `SessionConfig` for method chaining.

### Resuming Sessions

```java
var session = client.resumeSession(sessionId, new ResumeSessionConfig()
    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
```

### Session Operations

- `session.getSessionId()` - Get session identifier
- `session.send(prompt)` / `session.send(MessageOptions)` - Send message, returns `CompletableFuture<String>` (the message ID, useful for correlation)
- `session.sendAndWait(prompt)` / `session.sendAndWait(MessageOptions)` - Send and wait for response (60s timeout)
- `session.sendAndWait(options, timeoutMs)` - Send and wait with custom timeout
- `session.abort()` - Abort current processing
- `session.getMessages()` - Get all events/messages
- `session.setModel(modelId)` - Switch to a different model
- `session.setModel(modelId, reasoningEffort)` - Switch model with reasoning effort ("low", "medium", "high", "xhigh")
- `session.setModel(modelId, reasoningEffort, modelCapabilities)` - Switch model with `ModelCapabilitiesOverride` (since 1.3.0)
- `session.log(message)` / `session.log(message, "warning", false)` / `session.log(message, "error", false)` - Log to session timeline with level `"info"`, `"warning"`, or `"error"`
- `session.log(message, level, ephemeral, url)` - Log with a clickable URL link
- `session.close()` - Clean up resources

## Event Handling

### Event Subscription Pattern

Use `CompletableFuture` for waiting on session events:

```java
var done = new CompletableFuture<Void>();

session.on(event -> {
    if (event instanceof AssistantMessageEvent msg) {
        System.out.println(msg.getData().content());
    } else if (event instanceof SessionIdleEvent) {
        done.complete(null);
    }
});

session.send(new MessageOptions().setPrompt("Hello"));
done.get();
```

### Type-Safe Event Handling

Use the typed `on()` overload for compile-time safety:

```java
var done = new java.util.concurrent.CompletableFuture<Void>();

session.on(AssistantMessageEvent.class, msg -> {
    System.out.println(msg.getData().content());
});

session.on(SessionIdleEvent.class, idle -> {
    done.complete(null);
});
```

### Unsubscribing from Events

The `on()` method returns a `Closeable`:

```java
var subscription = session.on(event -> { /* handler */ });
// Later...
subscription.close();
```

### Event Types

Use pattern matching (Java 17+) for event handling:

```java
session.on(event -> {
    if (event instanceof UserMessageEvent userMsg) {
        // Handle user message
    } else if (event instanceof AssistantMessageEvent assistantMsg) {
        System.out.println(assistantMsg.getData().content());
    } else if (event instanceof AssistantMessageDeltaEvent delta) {
        System.out.print(delta.getData().deltaContent());
    } else if (event instanceof ToolExecutionStartEvent toolStart) {
        // Tool execution started
    } else if (event instanceof ToolExecutionCompleteEvent toolComplete) {
        // Tool execution completed
    } else if (event instanceof SessionStartEvent start) {
        // Session started
    } else if (event instanceof SessionIdleEvent idle) {
        // Session is idle (processing complete)
    } else if (event instanceof SessionErrorEvent error) {
        System.err.println("Error: " + error.getData().message());
    }
});
```

### Event Error Handling

Control how errors in event handlers are handled:

```java
// Set a custom error handler
session.setEventErrorHandler(ex -> {
    logger.error("Event handler error", ex);
});

// Or set the error propagation policy
session.setEventErrorPolicy(EventErrorPolicy.SUPPRESS_AND_LOG_ERRORS);
```

`EventErrorPolicy` values:
- `PROPAGATE_AND_LOG_ERRORS` - Stop event dispatch on error (default)
- `SUPPRESS_AND_LOG_ERRORS` - Continue dispatch, log the error

## Streaming Responses

### Enabling Streaming

Set `streaming(true)` in SessionConfig:

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

### Handling Streaming Events

Handle both delta events (incremental) and final events:

Requires Java 21+, but 25 preferred.

```java
var done = new CompletableFuture<Void>();

session.on(event -> {
    switch (event) {
        case AssistantMessageDeltaEvent delta ->
            // Incremental text chunk
            System.out.print(delta.getData().deltaContent());
        case AssistantReasoningDeltaEvent reasoningDelta ->
            // Incremental reasoning chunk (model-dependent)
            System.out.print(reasoningDelta.getData().deltaContent());
        case AssistantMessageEvent msg ->
            // Final complete message
            System.out.println("\n--- Final ---\n" + msg.getData().content());
        case AssistantReasoningEvent reasoning ->
            // Final reasoning content
            System.out.println("--- Reasoning ---\n" + reasoning.getData().content());
        case SessionIdleEvent idle ->
            done.complete(null);
        default -> { }
    }
});

session.send(new MessageOptions().setPrompt("Tell me a story"));
done.get();
```

Note: Final events (`AssistantMessageEvent`, `AssistantReasoningEvent`) are ALWAYS sent regardless of streaming setting.

## Custom Tools

### Defining Tools

Use `ToolDefinition.create()` with JSON Schema parameters and a `ToolHandler`:

```java
var tool = ToolDefinition.create(
    "get_weather",
    "Get weather for a location",
    Map.of(
        "type", "object",
        "properties", Map.of(
            "location", Map.of("type", "string", "description", "City name")
        ),
        "required", List.of("location")
    ),
    invocation -> {
        String location = (String) invocation.getArguments().get("location");
        return CompletableFuture.completedFuture("Sunny in " + location);
    }
);

var session = client.createSession(new SessionConfig()
    .setModel("gpt-5")
    .setTools(List.of(tool))
    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
```

### Type-Safe Tool Arguments

Use `getArgumentsAs()` for deserialization into a typed record or class:

```java
record WeatherArgs(String location, String unit) {}

var tool = ToolDefinition.create(
    "get_weather",
    "Get weather for a location",
    Map.of(
        "type", "object",
        "properties", Map.of(
            "location", Map.of("type", "string"),
            "unit", Map.of("type", "string", "enum", List.of("celsius", "fahrenheit"))
        ),
        "required", List.of("location")
    ),
    invocation -> {
        var args = invocation.getArgumentsAs(WeatherArgs.class);
        return CompletableFuture.completedFuture(
            Map.of("temp", 72, "unit", args.unit(), "location", args.location())
        );
    }
);
```

### Overriding Built-In Tools

```java
var override = ToolDefinition.createOverride(
    "built_in_tool_name",
    "Custom description",
    Map.of("type", "object", "properties", Map.of(...)),
    invocation -> CompletableFuture.completedFuture("custom result")
);
```

### Skipping Permission Checks (since 1.2.0)

Use `createSkipPermission()` to define a tool that bypasses the CLI's permission request flow:

```java
var tool = ToolDefinition.createSkipPermission(
    "safe_read_only_tool",
    "A tool that needs no permission confirmation",
    Map.of("type", "object", "properties", Map.of(...)),
    invocation -> CompletableFuture.completedFuture("result")
);
```

### Tool Return Types

- Return any JSON-serializable value (String, Map, List, record, POJO)
- The SDK automatically serializes the return value and sends it back to the CLI

### Tool Execution Flow

When Copilot invokes a tool, the client automatically:
1. Deserializes the arguments
2. Runs your handler function
3. Serializes the return value
4. Responds to the CLI

## Permission Handling

### Required Permission Handler

A permission handler is **mandatory** when creating or resuming sessions:

```java
// Approve all requests (for development/testing)
new SessionConfig()
    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)

// Custom permission logic
new SessionConfig()
    .setOnPermissionRequest((request, invocation) -> {
        if ("dangerous-action".equals(request.getKind())) {
            return CompletableFuture.completedFuture(
                new PermissionRequestResult().setKind(PermissionRequestResultKind.DENIED)
            );
        }
        return CompletableFuture.completedFuture(
            new PermissionRequestResult().setKind(PermissionRequestResultKind.APPROVED)
        );
    })
```

## User Input Handling

Handle user input requests from the agent:

```java
new SessionConfig()
    .setOnUserInputRequest((request, invocation) -> {
        System.out.println("Agent asks: " + request.getQuestion());
        String answer = scanner.nextLine();
        return CompletableFuture.completedFuture(
            new UserInputResponse()
                .setAnswer(answer)
                .setWasFreeform(true)
        );
    })
```

## System Message Customization

### Append Mode (Default - Preserves Guardrails)

```java
var session = client.createSession(new SessionConfig()
    .setModel("gpt-5")
    .setSystemMessage(new SystemMessageConfig()
        .setMode(SystemMessageMode.APPEND)
        .setContent("""
            <workflow_rules>
            - Always check for security vulnerabilities
            - Suggest performance improvements when applicable
            </workflow_rules>
            """))
    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
```

### Replace Mode (Full Control - Removes Guardrails)

```java
var session = client.createSession(new SessionConfig()
    .setModel("gpt-5")
    .setSystemMessage(new SystemMessageConfig()
        .setMode(SystemMessageMode.REPLACE)
        .setContent("You are a helpful assistant."))
    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
```

## File Attachments

Attach files to messages using `Attachment`:

```java
session.send(new MessageOptions()
    .setPrompt("Analyze this file")
    .setAttachments(List.of(
        new Attachment("file", "/path/to/file.java", "My File")
    ))
);
```

## Message Delivery Modes

Use the `mode` property in `MessageOptions`:

- `"enqueue"` - Queue message for processing (default)
- `"immediate"` - Process message immediately

```java
session.send(new MessageOptions()
    .setPrompt("...")
    .setMode("enqueue")
);
```

## Convenience: Send and Wait

Use `sendAndWait()` to send a message and block until the assistant responds:

```java
// With default 60-second timeout
AssistantMessageEvent response = session.sendAndWait("What is 2+2?").get();
System.out.println(response.getData().content());

// With custom timeout
AssistantMessageEvent response = session.sendAndWait(
    new MessageOptions().setPrompt("Write a long story"),
    120_000  // 120 seconds
).get();
```

## Multiple Sessions

Sessions are independent and can run concurrently:

```java
var session1 = client.createSession(new SessionConfig()
    .setModel("gpt-5")
    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();

var session2 = client.createSession(new SessionConfig()
    .setModel("claude-sonnet-4.5")
    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();

session1.send(new MessageOptions().setPrompt("Hello from session 1"));
session2.send(new MessageOptions().setPrompt("Hello from session 2"));
```

## Bring Your Own Key (BYOK)

Use custom API providers via `ProviderConfig`:

```java
// OpenAI
var session = client.createSession(new SessionConfig()
    .setProvider(new ProviderConfig()
        .setType("openai")
        .setBaseUrl("https://api.openai.com/v1")
        .setApiKey("sk-..."))
    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();

// Azure OpenAI
var session = client.createSession(new SessionConfig()
    .setProvider(new ProviderConfig()
        .setType("azure")
        .setAzure(new AzureOptions()
            .setEndpoint("https://my-resource.openai.azure.com")
            .setDeployment("gpt-4"))
        .setBearerToken("..."))
    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
```

## Session Lifecycle Management

### Listing Sessions

```java
var sessions = client.listSessions().get();
for (var metadata : sessions) {
    System.out.println("Session: " + metadata.getSessionId());
}
```

### Filtering Sessions

Use `SessionListFilter` to narrow results by working directory, git root, repository, or branch:

```java
var filter = new SessionListFilter()
    .setRepository("owner/repo")
    .setBranch("main");

var sessions = client.listSessions(filter).get();
```

### Deleting Sessions

```java
client.deleteSession(sessionId).get();
```

### Checking Connection State

```java
var state = client.getState();
```

### Lifecycle Event Subscription

```java
AutoCloseable subscription = client.onLifecycle(event -> {
    System.out.println("Lifecycle event: " + event);
});
// Later...
subscription.close();
```

### Filtered Lifecycle Events

Subscribe to specific lifecycle event types:

```java
AutoCloseable subscription = client.onLifecycle("session.created", event -> {
    System.out.println("New session created");
});
```

## Error Handling

### Standard Exception Handling

```java
try {
    var session = client.createSession(new SessionConfig()
        .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
    ).get();
    session.sendAndWait("Hello").get();
} catch (ExecutionException ex) {
    Throwable cause = ex.getCause();
    System.err.println("Error: " + cause.getMessage());
} catch (Exception ex) {
    System.err.println("Error: " + ex.getMessage());
}
```

### Session Error Events

Monitor `SessionErrorEvent` for runtime errors:

```java
session.on(SessionErrorEvent.class, error -> {
    System.err.println("Session Error: " + error.getData().message());
});
```

## Connectivity Testing

Use `ping()` to verify server connectivity:

```java
var response = client.ping("test message").get();
```

## Status and Authentication

```java
// Get CLI version and protocol info
var status = client.getStatus().get();

// Check authentication status
var authStatus = client.getAuthStatus().get();

// List available models
var models = client.listModels().get();
```

## Resource Cleanup

### Automatic Cleanup with try-with-resources

ALWAYS use try-with-resources for automatic disposal:

```java
try (var client = new CopilotClient()) {
    client.start().get();
    try (var session = client.createSession(new SessionConfig()
            .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get()) {
        // Use session...
    }
}
// Resources automatically cleaned up
```

### Manual Cleanup

If not using try-with-resources:

```java
var client = new CopilotClient();
try {
    client.start().get();
    // Use client...
} finally {
    client.stop().get();
}
```

## Best Practices

1. **Always use try-with-resources** for `CopilotClient` and `CopilotSession`
2. **Always provide a permission handler** - it is required for `createSession` and `resumeSession`
3. **Use `CompletableFuture`** properly - call `.get()` to block, or chain with `.thenApply()`/`.thenCompose()`
4. **Use `sendAndWait()`** for simple request-response patterns instead of manual event handling
5. **Handle `SessionErrorEvent`** for robust error handling
6. **Use pattern matching** (switch with sealed types) for event handling
7. **Enable streaming** for better UX in interactive scenarios
8. **Close event subscriptions** (`Closeable`) when no longer needed
9. **Use `SystemMessageMode.APPEND`** to preserve safety guardrails
10. **Provide descriptive tool names and descriptions** for better model understanding
11. **Handle both delta and final events** when streaming is enabled
12. **Use `getArgumentsAs()`** for type-safe tool argument deserialization

## Common Patterns

### Simple Query-Response

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

    try (var session = client.createSession(new SessionConfig()
            .setModel("gpt-5")
            .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get()) {

        var response = session.sendAndWait("What is 2+2?").get();
        System.out.println(response.getData().content());
    }
}
```

### Event-Driven Conversation

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

    try (var session = client.createSession(new SessionConfig()
            .setModel("gpt-5")
            .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get()) {

        var done = new CompletableFuture<Void>();

        session.on(AssistantMessageEvent.class, msg ->
            System.out.println(msg.getData().content()));

        session.on(SessionIdleEvent.class, idle ->
            done.complete(null));

        session.send(new MessageOptions().setPrompt("What is 2+2?"));
        done.get();
    }
}
```

### Multi-Turn Conversation

```java
try (var session = client.createSession(new SessionConfig()
        .setModel("gpt-5")
        .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get()) {

    var response1 = session.sendAndWait("What is the capital of France?").get();
    System.out.println(response1.getData().content());

    var response2 = session.sendAndWait("What is its population?").get();
    System.out.println(response2.getData().content());
}
```

### Tool with Complex Return Type

```java
record UserInfo(String id, String name, String email, String role) {}

var tool = ToolDefinition.create(
    "get_user",
    "Retrieve user information",
    Map.of(
        "type", "object",
        "properties", Map.of(
            "userId", Map.of("type", "string", "description", "User ID")
        ),
        "required", List.of("userId")
    ),
    invocation -> {
        String userId = (String) invocation.getArguments().get("userId");
        return CompletableFuture.completedFuture(
            new UserInfo(userId, "John Doe", "[email protected]", "Developer")
        );
    }
);
```

### Session Hooks

```java
var session = client.createSession(new SessionConfig()
    .setModel("gpt-5")
    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
    .setHooks(new SessionHooks()
        .setOnPreToolUse((input, invocation) -> {
            System.out.println("About to execute tool: " + input.getToolName());
            // Use static factory methods on PreToolUseHookOutput:
            // PreToolUseHookOutput.allow()
            // PreToolUseHookOutput.deny()
            // PreToolUseHookOutput.deny("reason")
            // PreToolUseHookOutput.ask()
            return CompletableFuture.completedFuture(PreToolUseHookOutput.allow());
        })
        .setOnPostToolUse((output, invocation) -> {
            System.out.println("Tool execution complete: " + output);
            return CompletableFuture.completedFuture(null);
        })
        .setOnUserPromptSubmitted((prompt, invocation) -> {
            // Intercept user prompts before processing
            return CompletableFuture.completedFuture(null);
        })
        .setOnSessionStart((event, invocation) -> {
            return CompletableFuture.completedFuture(null);
        })
        .setOnSessionEnd((event, invocation) -> {
            return CompletableFuture.completedFuture(null);
        }))
).get();
```

## MCP Server Configuration

Configure Model Context Protocol servers via `SessionConfig.setMcpServers()`:

### Stdio-Based MCP Server

```java
var mcpServers = Map.of(
    "my-server", new McpStdioServerConfig()
        .setCommand("node")
        .setArgs(List.of("path/to/server.js"))
);

var session = client.createSession(new SessionConfig()
    .setModel("gpt-5")
    .setMcpServers(mcpServers)
    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
```

### HTTP/SSE MCP Server

```java
var mcpServers = Map.of(
    "remote-server", new McpHttpServerConfig()
        .setUrl("https://my-mcp-server.example.com/sse")
);

var session = client.createSession(new SessionConfig()
    .setModel("gpt-5")
    .setMcpServers(mcpServers)
    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
```

## Model Capabilities Override (since 1.3.0)

Override model capabilities for BYOK or custom providers:

```java
var capabilities = new ModelCapabilitiesOverride()
    .setSupports(new ModelCapabilitiesOverride.Supports()
        .setVision(true)
        .setReasoningEffort(true))
    .setLimits(new ModelCapabilitiesOverride.Limits()
        .setMaxPromptTokens(128000));

var session = client.createSession(new SessionConfig()
    .setModel("custom-model")
    .setModelCapabilities(capabilities)
    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
```

© github · MIT · github/awesome-copilot

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой