Skip to main content

Steuerung und Warteschlangen

Mit zwei Interaktionsmustern können Benutzer Nachrichten senden, während der Agent bereits arbeitet: Steuerung lenkt den Agenten während eines laufenden Turns um, und Warteschlangenbildung puffert Nachrichten zur sequenziellen Verarbeitung, nachdem der aktuelle Durchlauf abgeschlossen ist.

Übersicht

Wenn eine Sitzung aktiv eine Interaktion verarbeitet, können eingehende Nachrichten auf eine von zwei Arten über das mode-Feld zugestellt werden:MessageOptions

ModusBehaviorAnwendungsfall
"immediate" (Lenkung)In die aktuelle LLM-Umwandlung eingefügt"Erstellen Sie diese Datei tatsächlich nicht – verwenden Sie einen anderen Ansatz"
"enqueue" (Warteschlangen)In die Warteschlange eingereiht und verarbeitet nach Abschluss des aktuellen Durchgangs"Danach beheben Sie auch die Tests"

Diagramm: Sequenzdiagramm mit dem beschriebenen Prozess.

Lenkung (Sofortiger Modus)

Die Lenkung sendet eine Nachricht, die direkt in den aktuellen Spielzug des Agenten eingespeist wird. Der Agent sieht die Nachricht in Echtzeit und passt seine Antwort entsprechend an – nützlich für die Kurskorrektur, ohne die Drehung abzubrechen.

TypeScript
import { CopilotClient } from "@github/copilot-sdk";

const client = new CopilotClient();
await client.start();

const session = await client.createSession({
    model: "gpt-4.1",
    onPermissionRequest: async () => ({ kind: "approve-once" }),
});

// Start a long-running task
const msgId = await session.send({
    prompt: "Refactor the authentication module to use sessions",
});

// While the agent is working, steer it
await session.send({
    prompt: "Actually, use JWT tokens instead of sessions",
    mode: "immediate",
});
Python
from copilot import CopilotClient, PermissionDecisionApproveOnce

async def main():
    client = CopilotClient()
    await client.start()

    session = await client.create_session(
        on_permission_request=lambda req, inv: PermissionDecisionApproveOnce(),
        model="gpt-4.1",
    )

    # Start a long-running task
    msg_id = await session.send(
        "Refactor the authentication module to use sessions",
    )

    # While the agent is working, steer it
    await session.send(
        "Actually, use JWT tokens instead of sessions",
        mode="immediate",
    )

    await client.stop()
Go
package main

import (
    "context"
    "log"
    copilot "github.com/github/copilot-sdk/go"
    "github.com/github/copilot-sdk/go/rpc"
)

func main() {
    ctx := context.Background()
    client := copilot.NewClient(nil)
    if err := client.Start(ctx); err != nil {
        log.Fatal(err)
    }
    defer client.Stop()

    session, err := client.CreateSession(ctx, &copilot.SessionConfig{
        Model: "gpt-4.1",
        OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
            return &rpc.PermissionDecisionApproveOnce{}, nil
        },
    })
    if err != nil {
        log.Fatal(err)
    }

    // Start a long-running task
    _, err = session.Send(ctx, copilot.MessageOptions{
        Prompt: "Refactor the authentication module to use sessions",
    })
    if err != nil {
        log.Fatal(err)
    }

    // While the agent is working, steer it
    _, err = session.Send(ctx, copilot.MessageOptions{
        Prompt: "Actually, use JWT tokens instead of sessions",
        Mode:   "immediate",
    })
    if err != nil {
        log.Fatal(err)
    }
}
.NET
using GitHub.Copilot;
using GitHub.Copilot.Rpc;

await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-4.1",
    OnPermissionRequest = (req, inv) =>
        Task.FromResult(PermissionDecision.ApproveOnce()),
});

// Start a long-running task
var msgId = await session.SendAsync(new MessageOptions
{
    Prompt = "Refactor the authentication module to use sessions"
});

// While the agent is working, steer it
await session.SendAsync(new MessageOptions
{
    Prompt = "Actually, use JWT tokens instead of sessions",
    Mode = "immediate"
});
Java
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.events.*;
import com.github.copilot.sdk.json.*;

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

    var session = client.createSession(
        new SessionConfig()
            .setModel("gpt-4.1")
            .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
    ).get();

    // Start a long-running task
    session.send(new MessageOptions()
        .setPrompt("Refactor the authentication module to use sessions")
    ).get();

    // While the agent is working, steer it
    session.send(new MessageOptions()
        .setPrompt("Actually, use JWT tokens instead of sessions")
        .setMode("immediate")
    ).get();
}

Funktionsweise der Steuerung intern

  1. Die Nachricht wird zur Warteschlange der Laufzeitumgebung ImmediatePromptProcessor hinzugefügt.
  2. Vor der nächsten LLM-Anfrage innerhalb des aktuellen Turns fügt der Prozessor die Nachricht in die Konversation ein.
  3. Der Agent sieht die Lenkungsnachricht als neue Benutzernachricht und passt seine Antwort an.
  4. Wenn der Abbiegevorgang abgeschlossen ist, bevor die Lenknachricht verarbeitet wird, wird er automatisch für den nächsten Abbiegevorgang in die reguläre Warteschlange verschoben.

Hinweis

Lenkungsmeldungen sind in der aktuellen Drehung am besten geeignet. Wenn sich der Agent bereits für einen Tool-Call verpflichtet hat, wird die Steuerung nach Abschluss dieses Calls wirksam, aber immer noch innerhalb desselben Turns.

Warteschlangen (Enqueue-Modus)

Das Warteschlangenpuffer speichert Nachrichten, die sequenziell verarbeitet werden, nachdem die aktuelle Bearbeitung abgeschlossen ist. Jede in die Warteschlange eingereihte Nachricht startet einen eigenen vollständigen Durchlauf. Dies ist der Standardmodus – wenn Sie weglassen mode, verwendet "enqueue"das SDK .

TypeScript
import { CopilotClient } from "@github/copilot-sdk";

const client = new CopilotClient();
await client.start();

const session = await client.createSession({
    model: "gpt-4.1",
    onPermissionRequest: async () => ({ kind: "approve-once" }),
});

// Send an initial task
await session.send({ prompt: "Set up the project structure" });

// Queue follow-up tasks while the agent is busy
await session.send({
    prompt: "Add unit tests for the auth module",
    mode: "enqueue",
});

await session.send({
    prompt: "Update the README with setup instructions",
    mode: "enqueue",
});

// Messages are processed in FIFO order after each turn completes
Python
from copilot import CopilotClient, PermissionDecisionApproveOnce

async def main():
    client = CopilotClient()
    await client.start()

    session = await client.create_session(
        on_permission_request=lambda req, inv: PermissionDecisionApproveOnce(),
        model="gpt-4.1",
    )

    # Send an initial task
    await session.send("Set up the project structure")

    # Queue follow-up tasks while the agent is busy
    await session.send(
        "Add unit tests for the auth module",
        mode="enqueue",
    )

    await session.send(
        "Update the README with setup instructions",
        mode="enqueue",
    )

    # Messages are processed in FIFO order after each turn completes
    await client.stop()
Go
package main

import (
    "context"
    copilot "github.com/github/copilot-sdk/go"
    "github.com/github/copilot-sdk/go/rpc"
)

func main() {
    ctx := context.Background()
    client := copilot.NewClient(nil)
    client.Start(ctx)

    session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
        Model: "gpt-4.1",
        OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
            return &rpc.PermissionDecisionApproveOnce{}, nil
        },
    })

    session.Send(ctx, copilot.MessageOptions{
        Prompt: "Set up the project structure",
    })

    session.Send(ctx, copilot.MessageOptions{
        Prompt: "Add unit tests for the auth module",
        Mode:   "enqueue",
    })

    session.Send(ctx, copilot.MessageOptions{
        Prompt: "Update the README with setup instructions",
        Mode:   "enqueue",
    })
}
// Send an initial task
session.Send(ctx, copilot.MessageOptions{
    Prompt: "Set up the project structure",
})

// Queue follow-up tasks while the agent is busy
session.Send(ctx, copilot.MessageOptions{
    Prompt: "Add unit tests for the auth module",
    Mode:   "enqueue",
})

session.Send(ctx, copilot.MessageOptions{
    Prompt: "Update the README with setup instructions",
    Mode:   "enqueue",
})

// Messages are processed in FIFO order after each turn completes
.NET
using GitHub.Copilot;
using GitHub.Copilot.Rpc;

public static class QueueingExample
{
    public static async Task Main()
    {
        await using var client = new CopilotClient();
        await using var session = await client.CreateSessionAsync(new SessionConfig
        {
            Model = "gpt-4.1",
            OnPermissionRequest = (req, inv) =>
                Task.FromResult(PermissionDecision.ApproveOnce()),
        });

        await session.SendAsync(new MessageOptions
        {
            Prompt = "Set up the project structure"
        });

        await session.SendAsync(new MessageOptions
        {
            Prompt = "Add unit tests for the auth module",
            Mode = "enqueue"
        });

        await session.SendAsync(new MessageOptions
        {
            Prompt = "Update the README with setup instructions",
            Mode = "enqueue"
        });
    }
}
// Send an initial task
await session.SendAsync(new MessageOptions
{
    Prompt = "Set up the project structure"
});

// Queue follow-up tasks while the agent is busy
await session.SendAsync(new MessageOptions
{
    Prompt = "Add unit tests for the auth module",
    Mode = "enqueue"
});

await session.SendAsync(new MessageOptions
{
    Prompt = "Update the README with setup instructions",
    Mode = "enqueue"
});

// Messages are processed in FIFO order after each turn completes
Java
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.events.*;
import com.github.copilot.sdk.json.*;

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

    var session = client.createSession(
        new SessionConfig()
            .setModel("gpt-4.1")
            .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
    ).get();

    // Send an initial task
    session.send(new MessageOptions().setPrompt("Set up the project structure")).get();

    // Queue follow-up tasks while the agent is busy
    session.send(new MessageOptions()
        .setPrompt("Add unit tests for the auth module")
        .setMode("enqueue")
    ).get();

    session.send(new MessageOptions()
        .setPrompt("Update the README with setup instructions")
        .setMode("enqueue")
    ).get();

    // Messages are processed in FIFO order after each turn completes
}

Funktionsweise der Warteschlangen intern

  1. Die Nachricht wird dem itemQueue der Sitzung als QueuedItem hinzugefügt.
  2. Wenn der aktuelle Durchlauf abgeschlossen ist und die Sitzung inaktiv wird, wird processQueuedItems() ausgeführt.
  3. Elemente werden in FIFO-Reihenfolge dequeuiert – jede Nachricht löst eine vollständige agentische Drehung aus.
  4. Wenn beim Ende der Drehung eine Lenkungsmeldung ausstehend war, wird sie an den Anfang der Warteschlange verschoben.
  5. Die Verarbeitung wird fortgesetzt, bis die Warteschlange leer ist, und dann gibt die Sitzung ein Leerlaufereignis aus.

Kombination von Steuerung und Warteschlangenverwaltung

Sie können beide Muster in einer einzigen Sitzung verwenden. Die Lenkung wirkt sich auf die aktuelle Drehung aus, während Nachrichten in der Warteschlange auf ihre eigenen Drehungen warten.

TypeScript
const session = await client.createSession({
    model: "gpt-4.1",
    onPermissionRequest: async () => ({ kind: "approve-once" }),
});

// Start a task
await session.send({ prompt: "Refactor the database layer" });

// Steer the current work
await session.send({
    prompt: "Make sure to keep backwards compatibility with the v1 API",
    mode: "immediate",
});

// Queue a follow-up for after this turn
await session.send({
    prompt: "Now add migration scripts for the schema changes",
    mode: "enqueue",
});
Python
session = await client.create_session(
    on_permission_request=lambda req, inv: PermissionDecisionApproveOnce(),
    model="gpt-4.1",
)

# Start a task
await session.send("Refactor the database layer")

# Steer the current work
await session.send(
    "Make sure to keep backwards compatibility with the v1 API",
    mode="immediate",
)

# Queue a follow-up for after this turn
await session.send(
    "Now add migration scripts for the schema changes",
    mode="enqueue",
)

Auswahl zwischen Lenkung und Warteschlangen

SzenarioPatternWarum?
Der Agent geht auf den falschen Pfad.
LenkungLeitet den aktuellen Turn um, ohne den Fortschritt zu verlieren.
Sie dachten an etwas, was der Agent auch tun sollte
WarteschlangenbildungStört die aktuelle Arbeit nicht; wird als Nächstes ausgeführt.
Agent ist dabei, einen Fehler zu machen
LenkungGreift ein, bevor der Fehler begangen wird
Sie möchten mehrere Vorgänge verketten
WarteschlangenbildungFIFO-Sortierung gewährleistet vorhersehbare Ausführung
Sie möchten der aktuellen Aufgabe Kontext hinzufügen
LenkungAgent integriert es in seine aktuelle Begründung
Sie möchten unabhängige Anforderungen zusammenfassen.
WarteschlangenbildungJeder bekommt seinen eigenen vollständigen Schritt mit klarem Kontext.

Erstellen einer Benutzeroberfläche mit Steuerung und Warteschlangen

Hier ist ein Muster zum Erstellen einer interaktiven Benutzeroberfläche, die beide Modi unterstützt:

import { CopilotClient, CopilotSession } from "@github/copilot-sdk";

interface PendingMessage {
    prompt: string;
    mode: "immediate" | "enqueue";
    sentAt: Date;
}

class InteractiveChat {
    private session: CopilotSession;
    private isProcessing = false;
    private pendingMessages: PendingMessage[] = [];

    constructor(session: CopilotSession) {
        this.session = session;

        session.on((event) => {
            if (event.type === "session.idle") {
                this.isProcessing = false;
                this.onIdle();
            }
            if (event.type === "assistant.message") {
                this.renderMessage(event);
            }
        });
    }

    async sendMessage(prompt: string): Promise<void> {
        if (!this.isProcessing) {
            this.isProcessing = true;
            await this.session.send({ prompt });
            return;
        }

        // Session is busy — let the user choose how to deliver
        // Your UI would present this choice (e.g., buttons, keyboard shortcuts)
    }

    async steer(prompt: string): Promise<void> {
        this.pendingMessages.push({
            prompt,
            mode: "immediate",
            sentAt: new Date(),
        });
        await this.session.send({ prompt, mode: "immediate" });
    }

    async enqueue(prompt: string): Promise<void> {
        this.pendingMessages.push({
            prompt,
            mode: "enqueue",
            sentAt: new Date(),
        });
        await this.session.send({ prompt, mode: "enqueue" });
    }

    private onIdle(): void {
        this.pendingMessages = [];
        // Update UI to show session is ready for new input
    }

    private renderMessage(event: unknown): void {
        // Render assistant message in your UI
    }
}

API-Referenz

Nachrichtenoptionen

SpracheFeldTypVorgabeDescription
Node.jsmode"enqueue" | "immediate""enqueue"Nachrichtenübermittlungsmodus
PythonmodeLiteral["enqueue", "immediate"]"enqueue"Nachrichtenübermittlungsmodus
GoModestring"enqueue"Nachrichtenübermittlungsmodus
.NETModestring?"enqueue"Nachrichtenübermittlungsmodus

Liefermodi

ModusAuswirkungWährend einer aktiven DrehungWährend des Leerlaufs
"enqueue"Warteschlange für nächsten SchrittWartezeiten in der FIFO-WarteschlangeStartet sofort eine neue Drehung.
"immediate"In die aktuelle Drehung einfügenVor dem nächsten LLM-Aufruf eingefügtStartet sofort eine neue Drehung.

Hinweis

Wenn sich die Sitzung im Leerlauf befindet (keine Verarbeitung), verhalten sich beide Modi identisch – die Nachricht startet sofort eine neue Drehung.

Bewährte Methoden

  1. Voreinstellung auf Warteschlange setzen – Verwenden Sie "enqueue" für die meisten Nachrichten (oder mode auslassen). Es ist vorhersagbar und riskiert keine Unterbrechung der laufenden Arbeit.

  2. Behalten Sie sich die Steuerung für Korrekturen vor – Verwenden Sie "immediate", wenn der Agent aktiv fehlerhaft handelt und Sie ihn korrigieren müssen, bevor es weitergeht.

  3. Halten Sie die Lenkungsnachrichten kurz – Der Agent muss die Kurskorrektur schnell verstehen. Lange, komplexe Lenkungsmeldungen können den aktuellen Kontext verwirren.

  4. Nicht übersteuern – Mehrere schnelle Lenkmeldungen können die Drehqualität beeinträchtigen. Wenn Sie die Richtung erheblich ändern müssen, sollten Sie die Drehung abbrechen und neu beginnen.

  5. Anzeigen des Warteschlangenstatus in der Benutzeroberfläche – Zeigen Sie die Anzahl der in die Warteschlange eingereihten Nachrichten an, damit Benutzer wissen, was aussteht. Lauschen Sie auf Leerlaufereignisse, um die Anzeige zu löschen.

  6. Bearbeiten Sie den Fallback vom Steuerungsvorgang zur Warteschlange– Wenn eine Steuerungsnachricht nach dem Abschluss des Steuerungsvorgangs eingeht, wird sie automatisch in die Warteschlange verschoben. Entwerfen Sie Ihre Benutzeroberfläche so, dass sie diesen Übergang widerspiegelt.

Siehe auch