# Изменение средств во время сеанса

Приложение может заменить средства, которые он предоставляет для динамического сеанса, не воссоздавая его. Например, веб-страница может предлагать различные средства, как пользователь перемещается, или клиент, который берет на себя сеанс, может принести свои собственные средства. Каждый пакет SDK заменяет полный набор инструментов клиента и обработчики, обслуживающие его в одном вызове.

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

> **Экспериментальный.** Замена средства упаковывает экспериментальный `session.tools.set` RPC и требует среды выполнения, поддерживающей ее.

## Замена средств этого клиента

Передайте полный набор инструментов, которые должен предоставить этот клиент. Он заменяет средства, предоставленные клиентом при создании или возобновлении сеанса, или в более ранней замене. Встроенные средства, MCP и подключаемые модули, а также средства, которые другие клиенты, подключенные к одному и тому же предложению сеансов, не влияют на них. Передайте пустой список, чтобы удалить все средства этого клиента.

Средства определяются точно так же, как они предназначены для создания сеанса, и средство без обработчика ведет себя так же, как это происходит.

<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 { defineTool } from "@github/copilot-sdk";
import { z } from "zod";

const searchIssues = defineTool("search_issues", {
    description: "Search the issues shown on the current page",
    parameters: z.object({ query: z.string().describe("Search text") }),
    handler: async ({ query }) => findIssues(query),
});

// Supply only the tools the current page provides.
await session.setTools([searchIssues]);

// Remove all of this client's tools.
await session.setTools([]);
```

</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 pydantic import BaseModel, Field
from copilot.tools import define_tool

class SearchIssuesParams(BaseModel):
    query: str = Field(description="Search text")

@define_tool(description="Search the issues shown on the current page")
async def search_issues(params: SearchIssuesParams) -> str:
    return await find_issues(params.query)

# Supply only the tools the current page provides.
await session.set_tools([search_issues])

# Remove all of this client's tools.
await session.set_tools([])
```

</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
type SearchIssuesParams struct {
    Query string `json:"query" jsonschema:"Search text"`
}

searchIssues := copilot.DefineTool(
    "search_issues",
    "Search the issues shown on the current page",
    func(params SearchIssuesParams, inv copilot.ToolInvocation) (string, error) {
        return findIssues(params.Query)
    },
)

// Supply only the tools the current page provides.
if err := session.SetTools(ctx, []copilot.Tool{searchIssues}); err != nil {
    log.Fatal(err)
}

// Remove all of this client's tools.
if err := session.SetTools(ctx, nil); err != nil {
    log.Fatal(err)
}
```

</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
var searchIssues = CopilotTool.DefineTool(
    ([Description("Search text")] string query) => FindIssues(query),
    factoryOptions: new AIFunctionFactoryOptions
    {
        Name = "search_issues",
        Description = "Search the issues shown on the current page",
    });

// Supply only the tools the current page provides.
await session.SetToolsAsync([searchIssues]);

// Remove all of this client's tools.
await session.SetToolsAsync([]);
```

`SetToolsAsync` вызывает экспериментальную диагностику `GHCP001` , которая подавляется с помощью `#pragma warning disable GHCP001` или уровня `<NoWarn>GHCP001</NoWarn>`проекта.

</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
var searchIssues = ToolDefinition.create(
    "search_issues",
    "Search the issues shown on the current page",
    Map.of(
        "type", "object",
        "properties", Map.of("query", Map.of("type", "string", "description", "Search text")),
        "required", List.of("query")),
    invocation -> CompletableFuture.completedFuture(
        findIssues((String) invocation.getArguments().get("query"))));

// Supply only the tools the current page provides.
session.setTools(List.of(searchIssues)).get();

// Remove all of this client's tools.
session.setTools(List.of()).get();
```

`setTools`имеет значение `@CopilotExperimental`, поэтому потребляемый класс или метод должен принять участие.`@AllowCopilotExperimental` См. статью ["Использование экспериментальных API](https://github.com/github/copilot-sdk/tree/main/java/README.md#using-experimental-apis)".

</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
#[derive(Deserialize, JsonSchema)]
struct SearchIssuesParams {
    /// Search text
    query: String,
}

let search_issues = define_tool(
    "search_issues",
    "Search the issues shown on the current page",
    |_inv, params: SearchIssuesParams| async move {
        Ok(ToolResult::Text(find_issues(&params.query).await))
    },
);

// Supply only the tools the current page provides.
session.set_tools(vec![search_issues]).await?;

// Remove all of this client's tools.
session.set_tools(Vec::new()).await?;
```

</div>

</div>

## Когда новые средства вступают в силу

- **Запросы модели.** Среда выполнения предлагает новые средства из следующего запроса модели агента. Этот запрос может быть частью поворота, который уже выполняется.
- **Обработчики.** Как только среда выполнения принимает замену, каждый инструмент, вызывающий сеанс, использует новые обработчики. Вызовы, которые уже выполняются на обработчиках, которые запустили их.
- **Отказ.** Если среда выполнения отклоняет замену, вызов завершается ошибкой, а предыдущие средства и обработчики остаются на месте. Среда выполнения отклоняет имена инструментов с недопустимыми символами и именами, которые уже предоставляет другой подключенный клиент.
- **Упорядочивание.** Одновременные замены в одном сеансе применяются одновременно, в том порядке, в который они сделаны.
- **Отмена.** В пакетах SDK, которые позволяют отменить вызов, отменяя его, пока более ранняя замена по-прежнему отправляет ничего. После отправки запроса отмена останавливает только ожидание: если среда выполнения принимает замену, новые обработчики по-прежнему вступают в силу.

## Замена инструментов во время поворота

Запрос модели, уже запущенный с предыдущими инструментами, поэтому агент по-прежнему может вызывать средство, которое вы только что удалили. Сеанс не отвечает на этот вызов, так как другой подключенный клиент может предоставить инструмент с тем же именем, чтобы вызов мог оставаться в ожидании до тех пор, пока очередь не прервана.

Если запущенный поворот по-прежнему может вызвать средство удаления, замените средства во время простоя сеанса, например после `session.idle` события или прерывания первого поворота. Замена обработчика средства под тем же именем безопасна во время поворота: вызовы, отправленные после того, как среда выполнения принимает замену, используйте новый обработчик.

## Справочник по SDK

| SDK | Метод |
|---|---|
| TypeScript | `session.setTools(tools)` |
| Python | `await session.set_tools(tools)` |
| Go | `session.SetTools(ctx, tools)` |
| .NET | `await session.SetToolsAsync(tools, cancellationToken)` |
| Java | 
`session.setTools(tools)`, который возвращает значение `CompletableFuture<Void>` |
| Rust | `session.set_tools(tools).await` |