Skip to main content

Mandantenfähigkeit und Serverbereitstellungen

Führen Sie das Copilot SDK in Mehrbenutzerserverbereitstellungen mit Sitzungsisolation für Zustand, Authentifizierung und Tools aus.

Am besten geeignet für: SaaS-Produkte, Partnerintegrationen, interne Plattformen und Back-End-Dienste, die gleichzeitige Benutzer verarbeiten.

Verwenden Sie dieses Handbuch, wenn

Verwenden Sie diesen Leitfaden, wenn Sie Folgendes erstellen:

  • Ein Mehrbenutzer-SaaS-Produkt, das Copilot-gestützte Agenten einbettet
  • Ein Backend für eine Partnerintegration, beispielsweise ein Muster im Stil von Copilot Studio oder Fabric
  • Jeder Server, der gleichzeitige Benutzer, Arbeitsbereiche, Mandanten oder Anforderungen verarbeitet
  • Eine freigegebene Laufzeit, bei der mehrere SDK-Clients eine Verbindung mit einem Copilot Laufzeitprozess herstellen

Dieser Leitfaden ist eine Schwester von Skalierung und Mehrinstanzenfähigkeit. Verwenden Sie dieses Handbuch für Topologie, Lastenausgleich und Speichermuster. Verwenden Sie dieses Handbuch für Optionen auf SDK-Ebene und Optionen für die Laufzeitisolation.

Schlüssel-SDK-Optionen

AuswahlVerwenden Sie es fürHinweise
mode: "empty"Deaktivieren von Umgebungsbetriebssystem-Tools und CLI-StandardwertenErforderlich für Szenarien mit mehreren Benutzern oder gemeinsam genutzten Szenarien.
sessionIdleTimeoutSecondsBereinigen von LeerlaufsitzungenFestlegen eines serverseitigen Timeouts für lange ausgeführte Prozesse.
baseDirectoryIsolieren COPILOT_HOME pro LaufzeitinstanzWird ignoriert, wenn eine Verbindung mit einer vorhandenen Laufzeit hergestellt wird.
sessionFsUmleitung des Dateisystemspeichers für Sitzungen weg vom lokalen DatenträgerMit Dateisystemanbietern je Sitzung koppeln.
RuntimeConnection.forUri(url)Teilen einer bereits laufenden RuntimeSprachnamen variieren; siehe Beispiele unten.
Pro Sitzung gitHubTokenAuthentifizierung auf den anfragenden Benutzer beschränkenVerwenden Sie dies anstelle eines gemeinsam genutzten Benutzertokens.

mode: "empty"

mode: "empty" deaktiviert standardmäßig optionales Copilot CLI-Verhalten. Im Servermodus mit mehreren Benutzern ist dies der sichere Basisplan, da Ihre Anwendung explizit entscheiden muss, auf welche Tools, MCP-Server, Fähigkeiten und Arbeitsbereichspfade eine Sitzung zugreifen kann.

Verwenden Sie für gemeinsam genutzte Server nicht die Standardeinstellung mode: "copilot-cli". Dieser Modus ist für CLI-ähnliche Codierungs-Agents vorgesehen und kann Umgebungshost-Dateisystemfunktionen verfügbar machen.

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

Legen Sie sessionIdleTimeoutSeconds auf Servern fest, damit inaktive Sitzungen automatisch beendet werden. Dies verhindert Zombie-Sitzungen in lang laufenden Prozessen und reduziert den Speicher- und Dateisystemdruck.

LanguageÖffentliche Option
TypescriptsessionIdleTimeoutSeconds
Pythonsession_idle_timeout_seconds
GoSessionIdleTimeoutSeconds
.NETSessionIdleTimeoutSeconds
JavasetSessionIdleTimeoutSeconds(...)
Rustwith_session_idle_timeout_seconds(...)

Verwenden Sie einen Wert, der der Lebensdauer einer Konversation in Ihrem Produkt entspricht. Bei Chat-Back-Ends ist in der Regel 15 bis 30 Minuten ein guter Ausgangspunkt. Verwenden Sie für Workflow-Agents ein längeres Timeout und explizites Löschen, wenn der Workflow abgeschlossen ist.

baseDirectory

baseDirectory legt COPILOT_HOME für eine Laufzeitinstanz fest. Verwenden Sie sie, um Laufzeitstatus, Anmeldeinformationen und Sitzungsdaten pro Prozess, Pod, Worker oder Mandantengrenze zu isolieren.

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

Die Laufzeit speichert den Sitzungszustand unter dem konfigurierten COPILOT_HOME, einschließlich session-state/{sessionId}. Wenn Ihre App mehrere Laufzeitinstanzen ausführt, weisen Sie jeder Instanz ein eigenes Verzeichnis zu, es sei denn, Sie verwenden absichtlich freigegebenen Speicher.

Wenn das SDK eine Verbindung mit einer bereits ausgeführten Laufzeit herstellt RuntimeConnection.forUri(url), baseDirectory wird vom SDK-Client ignoriert. Konfigurieren Sie COPILOT_HOME stattdessen für den Laufzeitprozess.

sessionFs

sessionFs registriert einen benutzerdefinierten Sitzungsdateisystemanbieter, sodass sitzungsbezogene Datei-E/A über den Anwendungsspeicher statt über die lokale Festplatte der Laufzeitumgebung geleitet werden kann. Verwenden Sie sie, wenn der lokale Datenträger kurzlebig ist, wenn der Sitzungszustand im Objektspeicher gespeichert werden muss oder wenn eine Plattform mandantenbezogene Speicherpfade erzwingen muss.

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

Konfigurieren Sie für Sprachen, die einen Provider-Callback bereitstellen, sessionFs auf Client-Ebene, und stellen Sie beim Erstellen oder Fortsetzen einer Sitzung einen sitzungsspezifischen Dateisystem-Handler bereit. Siehe Wiederaufnahme und Persistenz der Sitzung für Persistenzkonzepte und Speicherabschläge.

Überprüfte öffentliche SDK-Oberflächen:

LanguageKonfiguration auf ClientebeneSitzungsbasierter Anbieter
TypescriptsessionFs
createSessionFsAdapter / Anbieterrückrufe
Pythonsession_fscreate_session_fs_handler
GoSessionFSCreateSessionFSProvider
.NETSessionFsCreateSessionFsProvider
Rustwith_session_fs(...)with_session_fs_provider(...)

Java stellt derzeit keine überprüfte öffentliche sessionFs-Option zur Verfügung, sodass in diesem Handbuch kein Java sessionFs-Beispiel angezeigt wird.

RuntimeConnection.forUri(url)

Verwenden Sie eine externe Laufzeitverbindung, wenn mehrere SDK-Clients eine bereits ausgeführte Laufzeit gemeinsam nutzen sollten. Dies ist in Back-End-Diensten üblich, bei denen der Laufzeitprozess getrennt von Anforderungshandlern verwaltet wird.

LanguageExterne Laufzeitverbindung
TypescriptRuntimeConnection.forUri(url)
PythonRuntimeConnection.for_uri(url)
Gocopilot.URIConnection{URL: url}
.NETRuntimeConnection.ForUri(url)
JavasetCliUrl(url)
RustTransport::External { host, port, connection_token }

Externe Laufzeiten verwalten ihre eigene Authentifizierung und Speicherung auf Prozessebene. Übergeben Sie Token pro Sitzung an createSession oder resumeSession wenn Sie eine benutzerspezifische Authentifizierung benötigen.

Pro Sitzung gitHubToken

Legen Sie gitHubToken in jeder Sitzung fest, um die GitHub-Authentifizierung auf den anfordernden Benutzer zu beschränken. Dies unterscheidet sich von einem Token auf Clientebene, das den Laufzeitprozess authentifiziert.

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

Verwenden Sie sitzungsbezogene Tokens für den Ausschluss von Inhalten, das Modellrouting, Kontingentprüfungen und den benutzerspezifischen Copilot-Zugriff. Vermeiden Sie die Freigabe eines Diensttokens für alle Benutzer, es sei denn, Ihr Produkt verwendet absichtlich die Semantik des Dienstkontos.

Integration-ID

Partner, die Branding-Agents erstellen, können eine Integrations-ID für Mission Control-Anforderungen festlegen. Die Laufzeit liest GITHUB_COPILOT_INTEGRATION_ID und stempelt sie als Copilot-Integration-Id HTTP-Header für jede Mission Control-Anforderung.

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

Die Standardintegrations-ID lautet copilot-developer-cli. Verwenden Sie einen stabilen Wert wie my-product-agent für Attribution und Routing. Die Integrations-ID wird derzeit nur von der Umgebungsvariablen konfiguriert. Es handelt sich nicht um eine erstklassige SDK-Option.

Wenn das SDK die Laufzeit startet, übergeben Sie die Umgebungsvariable über die Client-Umgebungsoption. Wenn Sie eine Verbindung mit RuntimeConnection.forUri(url) herstellen, legen Sie die Umgebungsvariable direkt für den Laufzeitprozess selbst fest.

Isolationsgarantien auf Sitzungsebene

Die Isolation auf Sitzungsebene bedeutet, dass die Laufzeit benutzerspezifische Modell- und Zustandsinformationen auf eine Sitzung beschränkt und nicht in einem global gemeinsam genutzten Zustand hält.

OberflächeIsolationsverhalten
Cache der ModelllistePro Sitzung. Die Modellsuche verwendet den Cache der Modellliste der Sitzung.
SitzungszustandPro Sitzungs-ID unter COPILOT_HOME/session-state/{sessionId}.
GitHub IdentitätPro Sitzung, wenn gitHubToken für die Sitzung festgelegt wird.
ToolsExplizit in mode: "empty"; Umgebung in mode: "copilot-cli".
Dateisystem des HostsWird vom Laufzeitprozess gemeinsam genutzt, wenn Host-Tools verfügbar sind.

mode: "empty" macht freigegebene Laufzeitmuster lebensfähig: Es werden keine Umgebungsbetriebssystem-Tools verfügbar gemacht, es sei denn, Ihre Anwendung registriert oder lässt sie zu. Mit mode: "copilot-cli" wird der Zugriff auf das Dateisystem des Betriebssystems über den Hostprozess gemeinsam genutzt. Verwenden Sie diesen Modus daher nicht im Mehrbenutzer-Servermodus.

Der Sitzungszustand wird unter COPILOT_HOME/session-state/{sessionId} gespeichert, es sei denn, Sie leiten ihn über sessionFs um. Verwenden Sie eindeutige Sitzungs-IDs, die Ihre eigene Mandanten- oder Benutzergrenze enthalten, und erzwingen Sie die Zugriffssteuerung, bevor Sie Sitzungen fortsetzen oder löschen.

Mustervergleich

SchemaVerwenden Sie, wennTrade-offs
Muster 1: isolierte CLI pro BenutzerSie benötigen die stärkste Isolationsgrenze oder separate Prozessanmeldeinformationen pro Benutzer.Starke Isolation; höhere Ressourcenkosten. Siehe Skalierung und Mehrinstanzenfähigkeit.
Muster 2: gemeinsame CLI mit mode: "empty"Sie möchten, dass eine Laufzeit viele Benutzer bedient, während Ihre App Tools, Authentifizierung und Sitzungs-IDs steuert.Effiziente; erfordert sorgfältige Toolregistrierung, Zugriffstoken pro Sitzung und Zugriffsprüfungen auf Anwendungsebene.
Muster 3: HybridSie verlagern rechenintensive Aufgaben in Cloud-Sitzungen und weniger rechenintensive Aufgaben in lokale Sitzungen.Flexibel; erfordert Workload-Routing und Richtlinienverwaltung. Siehe Cloud-Sitzungen.

Muster 2: gemeinsame CLI mit mode: "empty"

In diesem Muster verbinden sich alle Benutzer über Ihr Back-End mit einem Laufzeitpool. Die Anwendung führt die Benutzerauthentifizierung aus, wählt eine Sitzungs-ID aus, übergibt das GitHub-Token des Benutzers in der Sitzung und stellt eine explizite Tool-Zulassungsliste bereit.

Diagramm: Flussdiagramm mit dem beschriebenen Prozess.

Verwenden Sie die folgenden Regeln:

  • Starten Sie den Client oder die Runtime immer in mode: "empty".
  • Verwenden Sie eindeutige Sitzungs-IDs, und speichern Sie Besitzermetadaten in Ihrer Anwendungsdatenbank.
  • Überprüfen Sie die Inhaberschaft vor resumeSession, deleteSession oder jeder UI-Aktion, die auf eine Sitzungs-ID verweist.
  • Übergeben Sie gitHubToken pro Sitzung, wenn Anforderungen als Benutzer ausgeführt werden sollen.
  • Registrieren Sie nur die Tools, die die Sitzung benötigt, und bevorzugen Sie quellqualifizierte Zulassungslisten wie custom:* oder mcp:search_docs.
  • Legen Sie sessionIdleTimeoutSeconds fest und löschen Sie abgeschlossene Workflow-Sitzungen explizit.

Häufige Fallstricke

  • mode: "empty"Vergessen . Der Standardmodus copilot-cli macht das CLI-Stilverhalten verfügbar und kann das Hostdateisystem über Umgebungstools verfügbar machen.
  • Keine Festlegung von sessionIdleTimeoutSeconds. Server mit langen Laufzeiten können inaktive Sitzungen ansammeln, wenn diese nicht bereinigt werden.
  • Ein gitHubToken für mehrere Benutzer gemeinsam nutzen, anstatt ein sitzungsspezifisches Token zu übergeben.
  • Blindes Vertrauen in vom Client übermittelte Sitzungs-IDs, ohne im Backend ihre Zugehörigkeit zu prüfen.
  • Festlegen baseDirectory auf einem Client, der eine Verbindung mit einer vorhandenen Laufzeit herstellt und erwartet, dass der Laufzeitspeicher verschoben wird. Konfigurieren Sie stattdessen den Laufzeitprozess.
  • Das Zulassen weit gefasster Toolmuster wie builtin:*, ohne zu prüfen, ob jedes Tool für Ihre Benutzer geeignet ist.

Siehe auch