Skip to main content

Multilocação e implantações de servidores

Execute o SDK Copilot em implantações de servidor multiusuário com isolamento por sessão para estado, autenticação e ferramentas.

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. 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çãoUse-o paraObservações
mode: "empty"Desativação das ferramentas nativas do sistema operacional e das configurações padrão da CLINecessário para cenários compartilhados ou multiusuários.
sessionIdleTimeoutSecondsLimpar sessões ociosasDefina um timeout no lado do servidor para processos de longa duração.
baseDirectoryIsolando COPILOT_HOME por instância de runtimeIgnorado ao se conectar a um runtime existente.
sessionFsEncaminhamento do armazenamento do sistema de arquivos da sessão para fora do disco localEmparelhar com provedores de sistema de arquivos por sessão.
RuntimeConnection.forUri(url)Compartilhando um runtime já em execuçãoOs nomes de idioma variam; veja os exemplos abaixo.
Por sessão gitHubTokenRestringindo a autenticação ao usuário solicitantePrefira 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.

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-4.1",
    availableTools: ["custom:lookupOrder", "custom:createTicket"],
    gitHubToken: user.githubToken,
});
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-4.1",
    available_tools=["custom:lookupOrder", "custom:createTicket"],
    github_token=user.github_token,
    on_permission_request=PermissionHandler.approve_all,
)
Go
package main

import (
    "context"
    "fmt"

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

type appUser struct {
    ID          string
    GitHubToken string
}

func main() {
    ctx := context.Background()
    runtimeInstanceID := "instance-1"
    runtimeURL := "http://127.0.0.1:8080"
    requestID := "req-1"
    user := appUser{ID: "alice", GitHubToken: "YOUR_GITHUB_TOKEN"}

    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-4.1",
        AvailableTools: []string{"custom:lookupOrder", "custom:createTicket"},
        GitHubToken:    user.GitHubToken,
    })
    _ = session
    _ = err
}
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-4.1",
    AvailableTools: []string{"custom:lookupOrder", "custom:createTicket"},
    GitHubToken:    user.GitHubToken,
})
.NET
using GitHub.Copilot;

var runtimeInstanceId = "instance-1";
var runtimeUrl = "http://127.0.0.1:8080";
var requestId = "req-1";
var user = new { Id = "alice", GitHubToken = "YOUR_GITHUB_TOKEN" };

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-4.1",
    AvailableTools = ["custom:lookupOrder", "custom:createTicket"],
    GitHubToken = user.GitHubToken,
});
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-4.1",
    AvailableTools = ["custom:lookupOrder", "custom:createTicket"],
    GitHubToken = user.GitHubToken,
});
Java
import java.util.List;
import com.github.copilot.CopilotClient;
import com.github.copilot.rpc.CopilotClientOptions;
import com.github.copilot.rpc.CopilotClientMode;
import com.github.copilot.rpc.SessionConfig;

public class MultiTenancyExample {
    record User(String id, String gitHubToken) {}

    public static void main(String[] args) throws Exception {
        String runtimeUrl = "http://localhost:4321";
        String requestId = "req-1";
        User user = new User("u1", "ghu_token");

        // 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-4.1")
            .setAvailableTools(List.of("custom:lookupOrder", "custom:createTicket"))
            .setGitHubToken(user.gitHubToken())
        ).get();
    }
}
// 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-4.1")
    .setAvailableTools(List.of("custom:lookupOrder", "custom:createTicket"))
    .setGitHubToken(user.gitHubToken())
).get();
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-4.1")
        .with_available_tools(["custom:lookupOrder", "custom:createTicket"])
        .with_github_token(user.github_token),
).await?;

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.

LinguagemOpção pública
TypeScriptsessionIdleTimeoutSeconds
Pythonsession_idle_timeout_seconds
GoSessionIdleTimeoutSeconds
.NETSessionIdleTimeoutSeconds
JavasetSessionIdleTimeoutSeconds(...)
Rustwith_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-o para isolar o estado do runtime, as credenciais e os dados de sessão por processo, pod, trabalho ou limite de locatário.

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

O runtime armazena o estado da sessão no configurado COPILOT_HOME, 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-o quando o disco local for efêmero, quando o estado da sessão precisar ficar no armazenamento de objetos ou quando uma plataforma precisar impor caminhos de armazenamento específicos por locatário.

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 para obter conceitos de persistência e compensações de armazenamento.

Superfícies do SDK público verificadas:

LinguagemConfiguração no nível do clienteFornecedor por sessão
TypeScriptsessionFs
createSessionFsAdapter / callbacks do provedor
Pythonsession_fscreate_session_fs_handler
GoSessionFSCreateSessionFSProvider
.NETSessionFsCreateSessionFsProvider
Rustwith_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.

LinguagemConexão com ambiente de execução externo
TypeScriptRuntimeConnection.forUri(url)
PythonRuntimeConnection.for_uri(url)
Gocopilot.URIConnection{URL: url}
.NETRuntimeConnection.ForUri(url)
JavasetCliUrl(url)
RustTransport::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.

const session = await client.createSession({
    sessionId: `user-${user.id}-support`,
    model: "gpt-4.1",
    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.

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 em 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ícieComportamento de isolamento
Cache de lista de modelosPor sessão. A pesquisa de modelo usa o cache de lista de modelos da sessão.
Estado da sessãoPor ID de sessão em COPILOT_HOME/session-state/{sessionId}.
Identidade do GitHubPor sessão, quando gitHubToken é definido na sessão.
ToolsExplícito em mode: "empty"; implícito em mode: "copilot-cli".
Sistema de arquivos de hostCompartilhado 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

PatternUsar quandoCompensações
Padrão 1: CLI isolada por usuárioVocê 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.
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íbridoVocê 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.

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.

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.
  • Definir baseDirectory em um cliente que se conecta a um runtime existente esperando mover o armazenamento do runtime. 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