# Multilocação e implantações de servidores

O modo de servidor multiusuário significa executar o SDK do Copilot a partir de um código de back-end que atende a mais de um usuário, locatário, workspace ou conta de integração. Nessa configuração, o aplicativo é responsável pelo roteamento das solicitações e pela autorização, enquanto o SDK e o runtime fornecem estado por sessão, autenticação por sessão e registro explícito de ferramentas, para que a sessão de um usuário não herde as ferramentas nem a identidade de outro usuário.

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

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

**Melhor para:** Produtos saaS, integrações de parceiros, plataformas internas e serviços de back-end que lidam com usuários simultâneos.

## Use este guia quando

Use este guia ao criar:

* Um produto SaaS multiusuário que incorpora agentes com tecnologia Copilot
* Um back-end para uma integração com parceiros, como um padrão no estilo do Copilot Studio ou do Fabric
* Qualquer servidor que gerencia usuários simultâneos, espaços de trabalho, tenants ou solicitações
* Um runtime compartilhado no qual vários clientes do SDK se conectam a um processo de runtime do Copilot

Este guia é um guia complementar a [Escalabilidade e multitenância](/pt/copilot/how-tos/copilot-sdk/setup/scaling). Use esse guia para topologia, balanceamento de carga e padrões de armazenamento. Use este guia para opções no nível do SDK e opções de isolamento de runtime.

## Principais opções do SDK

| Opção                           | Use-o para                                                                                   | Observações                                                            |
| ------------------------------- | -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| `mode: "empty"`                 | Desativação das ferramentas nativas do sistema operacional e das configurações padrão da CLI | Necessário para cenários compartilhados ou multiusuários.              |
| `sessionIdleTimeoutSeconds`     | Limpar sessões ociosas                                                                       | Defina um timeout no lado do servidor para processos de longa duração. |
| `baseDirectory`                 | Isolando `COPILOT_HOME` por instância de runtime                                             | Ignorado ao se conectar a um runtime existente.                        |
| `sessionFs`                     | Encaminhamento do armazenamento do sistema de arquivos da sessão para fora do disco local    | Emparelhe com provedores de sistema de arquivos por sessão.            |
| `RuntimeConnection.forUri(url)` | Compartilhando um runtime já em execução                                                     | Os nomes de idioma variam; veja os exemplos abaixo.                    |
| Por sessão `gitHubToken`        | Autenticação com escopo para o usuário solicitante.                                          | Prefira isso em vez de um único token de usuário compartilhado.        |

### `mode: "empty"`

`mode: "empty"` desabilita o comportamento opcional da CLI Copilot por padrão. No modo de servidor multiusuário, essa é a linha de base segura porque seu aplicativo deve decidir explicitamente quais ferramentas, servidores MCP, habilidades e caminhos de workspace uma sessão pode acessar.

Não use o padrão `mode: "copilot-cli"` para servidores compartilhados. Esse modo destina-se a agentes de programação do tipo CLI e pode expor capacidades do sistema de arquivos do host no ambiente.

<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, RuntimeConnection } from "@github/copilot-sdk";

// baseDirectory and sessionIdleTimeoutSeconds apply when the SDK spawns the
// runtime. With RuntimeConnection.forUri(...) configure COPILOT_HOME and the
// idle timeout on the runtime process itself.
const client = new CopilotClient({
    mode: "empty",
    connection: RuntimeConnection.forUri(process.env.COPILOT_RUNTIME_URL!),
});

const session = await client.createSession({
    sessionId: `user-${user.id}-${crypto.randomUUID()}`,
    model: "gpt-5.4",
    availableTools: ["custom:lookupOrder", "custom:createTicket"],
    gitHubToken: user.githubToken,
});
```

</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(
    mode="empty",
    base_directory=f"/var/lib/my-app/copilot/{runtime_instance_id}",
    session_idle_timeout_seconds=900,
    connection=RuntimeConnection.for_uri(runtime_url),
)
await client.start()

session = await client.create_session(
    session_id=f"user-{user.id}-{request_id}",
    model="gpt-5.4",
    available_tools=["custom:lookupOrder", "custom:createTicket"],
    github_token=user.github_token,
    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
client := copilot.NewClient(&copilot.ClientOptions{
    Mode:                      copilot.ModeEmpty,
    BaseDirectory:             fmt.Sprintf("/var/lib/my-app/copilot/%s", runtimeInstanceID),
    SessionIdleTimeoutSeconds: 900,
    Connection:                copilot.URIConnection{URL: runtimeURL},
})

session, err := client.CreateSession(ctx, &copilot.SessionConfig{
    SessionID:      fmt.Sprintf("user-%s-%s", user.ID, requestID),
    Model:          "gpt-5.4",
    AvailableTools: []string{"custom:lookupOrder", "custom:createTicket"},
    GitHubToken:    user.GitHubToken,
})
```

</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 client = new CopilotClient(new CopilotClientOptions
{
    Mode = CopilotClientMode.Empty,
    BaseDirectory = $"/var/lib/my-app/copilot/{runtimeInstanceId}",
    SessionIdleTimeoutSeconds = 900,
    Connection = RuntimeConnection.ForUri(runtimeUrl),
});

await using var session = await client.CreateSessionAsync(new SessionConfig
{
    SessionId = $"user-{user.Id}-{requestId}",
    Model = "gpt-5.4",
    AvailableTools = ["custom:lookupOrder", "custom:createTicket"],
    GitHubToken = user.GitHubToken,
});
```

</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
// setCopilotHome and setSessionIdleTimeoutSeconds are ignored when
// setCliUrl is used; configure those on the runtime process instead.
var client = new CopilotClient(new CopilotClientOptions()
    .setMode(CopilotClientMode.EMPTY)
    .setCliUrl(runtimeUrl)
);

var session = client.createSession(new SessionConfig()
    .setSessionId("user-" + user.id() + "-" + requestId)
    .setModel("gpt-5.4")
    .setAvailableTools(List.of("custom:lookupOrder", "custom:createTicket"))
    .setGitHubToken(user.gitHubToken())
).get();
```

</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::path::PathBuf;
use github_copilot_sdk::{Client, ClientOptions, Transport};
use github_copilot_sdk::mode::ClientMode;
use github_copilot_sdk::types::SessionConfig;

let client = Client::start(
    ClientOptions::new()
        .with_mode(ClientMode::Empty)
        .with_base_directory(PathBuf::from(format!(
            "/var/lib/my-app/copilot/{runtime_instance_id}"
        )))
        .with_session_idle_timeout_seconds(900)
        .with_transport(Transport::External {
            host: runtime_host.to_string(),
            port: runtime_port,
            connection_token: None,
        }),
).await?;

let session = client.create_session(
    SessionConfig::default()
        .with_session_id(format!("user-{}-{request_id}", user.id))
        .with_model("gpt-5.4")
        .with_available_tools(["custom:lookupOrder", "custom:createTicket"])
        .with_github_token(user.github_token),
).await?;
```

</div>

</div>

### `sessionIdleTimeoutSeconds`

Defina `sessionIdleTimeoutSeconds` em servidores para que as sessões inativas sejam limpas automaticamente. Isso impede sessões zumbis em processos de execução longa e reduz a pressão de memória e sistema de arquivos.

| Linguagem  | Opção pública                            |
| ---------- | ---------------------------------------- |
| TypeScript | `sessionIdleTimeoutSeconds`              |
| Python     | `session_idle_timeout_seconds`           |
| Go         | `SessionIdleTimeoutSeconds`              |
| .NET       | `SessionIdleTimeoutSeconds`              |
| Java       | `setSessionIdleTimeoutSeconds(...)`      |
| Rust       | `with_session_idle_timeout_seconds(...)` |

Use um valor que corresponda ao tempo de duração da conversa do seu produto. Para back-ends de chat, 15 a 30 minutos geralmente é um bom ponto de partida. Para agentes de fluxo de trabalho, use um tempo limite maior e uma exclusão explícita quando o fluxo de trabalho for concluído.

### `baseDirectory`

`baseDirectory` define `COPILOT_HOME` para uma instância de runtime. Use para isolar o estado de tempo de execução, credenciais e dados de sessão por processo, pod, worker ou limite de tenant.

```typescript
const client = new CopilotClient({
    mode: "empty",
    baseDirectory: `/var/lib/my-app/copilot/runtime-${process.env.HOSTNAME}`,
    sessionIdleTimeoutSeconds: 900,
});
```

O tempo de execução armazena o estado da sessão no `COPILOT_HOME`, configurado, incluindo `session-state/{sessionId}`. Se o aplicativo executar várias instâncias de runtime, dê a cada instância um diretório distinto, a menos que você use intencionalmente o armazenamento compartilhado.

Quando o SDK se conecta a um runtime já em execução com `RuntimeConnection.forUri(url)`, `baseDirectory` é ignorado pelo cliente do SDK. Configure `COPILOT_HOME` no processo de execução em vez disso.

### `sessionFs`

`sessionFs` registra um provedor personalizado de sistema de arquivos de sessão para que a E/S de arquivos com escopo de sessão possa ser roteada por meio do armazenamento do aplicativo em vez do disco local do ambiente de execução. Use quando o disco local for efêmero, quando o estado da sessão precisar residir no armazenamento de objetos ou quando uma plataforma precisar impor caminhos de armazenamento específicos para cada tenant.

```typescript
const client = new CopilotClient({
    mode: "empty",
    sessionFs: {
        initialCwd: "/workspace",
        sessionStatePath: "/session-state",
        conventions: "posix",
    },
});
```

Para linguagens que expõem um callback do provedor, configure `sessionFs` no nível do cliente e forneça um manipulador do sistema de arquivos para cada sessão ao criar ou retomar uma sessão. Consulte [Retomada e persistência da sessão](/pt/copilot/how-tos/copilot-sdk/features/session-persistence) para obter conceitos de persistência e compensações de armazenamento.

Superfícies do SDK público verificadas:

| Linguagem                                      | Configuração no nível do cliente | Provedor por sessão.            |
| ---------------------------------------------- | -------------------------------- | ------------------------------- |
| TypeScript                                     | `sessionFs`                      |                                 |
| `createSessionFsAdapter`/callbacks do provedor |                                  |                                 |
| Python                                         | `session_fs`                     | `create_session_fs_handler`     |
| Go                                             | `SessionFS`                      | `CreateSessionFSProvider`       |
| .NET                                           | `SessionFs`                      | `CreateSessionFsProvider`       |
| Rust                                           | `with_session_fs(...)`           | `with_session_fs_provider(...)` |

Java atualmente não expõe uma opção `sessionFs` pública verificada, portanto, este guia não mostra um exemplo de Java `sessionFs`.

### `RuntimeConnection.forUri(url)`

Use uma conexão de tempo de execução externa quando vários clientes do SDK precisarem compartilhar um tempo de execução já em execução. Isso é comum em serviços de back-end em que o processo de runtime é gerenciado separadamente dos manipuladores de solicitação.

| Linguagem  | Conexão com ambiente de execução externo               |
| ---------- | ------------------------------------------------------ |
| TypeScript | `RuntimeConnection.forUri(url)`                        |
| Python     | `RuntimeConnection.for_uri(url)`                       |
| Go         | `copilot.URIConnection{URL: url}`                      |
| .NET       | `RuntimeConnection.ForUri(url)`                        |
| Java       | `setCliUrl(url)`                                       |
| Rust       | `Transport::External { host, port, connection_token }` |

Os runtimes externos gerenciam sua própria autenticação e armazenamento em nível de processo. Passe tokens por sessão em `createSession` ou `resumeSession` quando precisar de autenticação específica do usuário.

### Por sessão `gitHubToken`

Defina `gitHubToken` em cada sessão para restringir o escopo da autenticação do GitHub ao usuário solicitante. Isso é diferente de um token no nível do cliente, que autentica o processo de runtime.

```typescript
const session = await client.createSession({
    sessionId: `user-${user.id}-support`,
    model: "gpt-5.4",
    availableTools: ["custom:*"],
    gitHubToken: user.githubToken,
});
```

Use tokens por sessão para exclusão de conteúdo, roteamento de modelos, verificações de cotas e acesso ao Copilot específico do usuário. Evite compartilhar um token de serviço entre usuários, a menos que seu produto use intencionalmente a semântica de conta de serviço.

## ID de integração

Os parceiros que criam agentes de marca podem definir uma ID de integração para solicitações de Controle de Missão. O runtime lê `GITHUB_COPILOT_INTEGRATION_ID` e o define como o cabeçalho HTTP `Copilot-Integration-Id` em cada solicitação do Mission Control.

```bash
GITHUB_COPILOT_INTEGRATION_ID=my-product-agent copilot --headless --port 4321
```

A ID de integração padrão é `copilot-developer-cli`. Use um valor estável, como `my-product-agent` para atribuição e roteamento. A ID de integração está configurada apenas por variável de ambiente; não é uma opção de SDK de primeira classe.

Se o SDK gerar o runtime, passe a variável de ambiente pela opção de ambiente do cliente. Se você se conectar com `RuntimeConnection.forUri(url)`, defina a variável de ambiente no próprio processo de tempo de execução.

## Garantias de isolamento em nível de sessão

O isolamento no nível da sessão significa que o runtime mantém as informações de estado e modelo específicas do usuário no escopo de uma sessão, não no estado compartilhado global.

| Superfície                  | Comportamento de isolamento                                                             |
| --------------------------- | --------------------------------------------------------------------------------------- |
| Cache de lista de modelos   | Por sessão. A pesquisa de modelo usa o cache de lista de modelos da sessão.             |
| Estado da sessão            | ID por sessão em `COPILOT_HOME/session-state/{sessionId}`.                              |
| Identidade do GitHub        | Por sessão, quando `gitHubToken` é definido na sessão.                                  |
| Tools                       | Explícito em `mode: "empty"`; ambiente em `mode: "copilot-cli"`.                        |
| Sistema de arquivos de host | Compartilhado pelo processo de runtime se as ferramentas de host estiverem disponíveis. |

`mode: "empty"` é o que torna os padrões de runtime compartilhados viáveis: nenhuma ferramenta de sistema operacional ambiente é exposta, a menos que seu aplicativo registre ou permita. Com `mode: "copilot-cli"`, o acesso ao sistema de arquivos do sistema operacional é compartilhado por meio do processo de host, portanto, não use esse modo para o modo de servidor multiusuário.

O estado da sessão é armazenado em `COPILOT_HOME/session-state/{sessionId}`, a menos que você o direcione por `sessionFs`. Use IDs de sessão exclusivas que incluem seu próprio locatário ou limite de usuário e imponha o controle de acesso antes de retomar ou excluir sessões.

## Comparação de padrões

| Pattern                                         | Usar quando                                                                                                                             | Compensações                                                                                                                                                          |
| ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Padrão 1: CLI isolada por usuário               | Você precisa do limite de isolamento mais forte ou das credenciais de processo separadas por usuário.                                   | Isolamento forte; custo de recurso mais alto. Consulte [Escalabilidade e multitenância](/pt/copilot/how-tos/copilot-sdk/setup/scaling).                               |
| Padrão 2: CLI compartilhada com `mode: "empty"` | Você deseja que um runtime atenda a muitos usuários enquanto seu aplicativo controla as ferramentas, a autenticação e as IDs de sessão. | Eficiente; requer um registro cuidadoso de ferramentas, tokens por sessão e verificações de acesso no nível do aplicativo.                                            |
| Padrão 3: híbrido                               | Você roteia o trabalho de computação pesada para sessões de nuvem e trabalho leve para sessões locais.                                  | Flexível; requer o roteamento de carga de trabalho e o tratamento de políticas. Consulte [Sessões de nuvem](/pt/copilot/how-tos/copilot-sdk/features/cloud-sessions). |

### Padrão 2: CLI compartilhada com `mode: "empty"`

Nesse padrão, todos os usuários se conectam por meio do back-end a um pool de runtime. O aplicativo executa a autenticação do usuário, escolhe uma ID de sessão, passa o token GitHub do usuário na sessão e fornece uma lista de permissões de ferramenta explícita.

![Diagrama: Fluxograma mostrando o processo descrito.](/assets/images/help/copilot/copilot-sdk/setup-multi-tenancy-diagram-0.png)

Use estas regras:

* Sempre inicie o cliente ou o runtime em `mode: "empty"`.
* Use IDs de sessão exclusivas e armazene metadados de propriedade no banco de dados do aplicativo.
* Verifique a titularidade antes de `resumeSession`, `deleteSession` ou qualquer ação da interface do usuário que faça referência a um ID de sessão.
* Forneça `gitHubToken` em cada sessão quando as solicitações devem ser executadas em nome do usuário.
* Registre apenas as ferramentas que a sessão necessita e prefira listas de permissões com origem especificada, como `custom:*` ou `mcp:search_docs`.
* Defina `sessionIdleTimeoutSeconds` e exclua as sessões de fluxo de trabalho concluídas explicitamente.

## Armadilhas comuns

* Esquecendo `mode: "empty"`. O modo padrão `copilot-cli` expõe um comportamento no estilo de CLI e pode expor o sistema de arquivos do host por meio de ferramentas disponíveis no ambiente.
* Não definir `sessionIdleTimeoutSeconds`. Servidores que permanecem em execução por longos períodos podem acumular sessões ociosas se não as encerrarem.
* Compartilhando um `gitHubToken` entre usuários em vez de passar um token por sessão.
* Confiando em IDs de sessão fornecidas pelo cliente sem verificar a propriedade em seu back-end.
* Configurando `baseDirectory` em um cliente que se conecta a um ambiente de execução existente e esperando que ele mova o armazenamento do ambiente de execução. Em vez disso, configure o processo de runtime.
* Permitir padrões de ferramentas amplos, como `builtin:*` sem examinar se cada ferramenta é apropriada para seus usuários.

## Consulte também

* [Escalabilidade e multitenância](/pt/copilot/how-tos/copilot-sdk/setup/scaling): topologias de implantação, padrões de armazenamento e comparações de isolamento
* [Configuração de serviços de back-end](/pt/copilot/how-tos/copilot-sdk/setup/backend-services): executando o ambiente de execução no modo servidor sem interface gráfica
* [BYOK (Bring Your Own Key - traga sua própria chave)](/pt/copilot/how-tos/copilot-sdk/auth/byok): usando suas próprias credenciais de provedor de modelo
* [Sessões de nuvem](/pt/copilot/how-tos/copilot-sdk/features/cloud-sessions): roteamento de trabalho selecionado para sessões de nuvem
* [Retomada e persistência da sessão](/pt/copilot/how-tos/copilot-sdk/features/session-persistence): gerenciando o estado de sessão retomável
* [Features](/pt/copilot/how-tos/copilot-sdk/features): ferramentas, eventos, ganchos e recursos avançados do SDK