Skip to main content

Direção e fila

Dois padrões de interação permitem que os usuários enviem mensagens enquanto o agente já está trabalhando: direcionamento redireciona o agente no meio da interação, e enfileiramento armazena mensagens em buffer para processamento sequencial após a conclusão da interação atual.

Overview

Quando uma sessão está processando ativamente uma vez, as mensagens de entrada podem ser entregues em um dos dois modos por meio do mode campo no MessageOptions:

ModoBehaviorCaso de uso
"immediate" (direção)Injetado na atual etapa do LLM"Na verdade, não crie esse arquivo — use uma abordagem diferente"
"enqueue" (enfileiramento)Enfileirado e processado após a conclusão do turno atual"Depois disso, corrija também os testes"

Diagrama: diagrama de sequência mostrando o processo descrito.

Direção (modo imediato)

O controle envia uma mensagem que é injetada diretamente no turno atual do agente. O agente vê a mensagem em tempo real e ajusta sua resposta adequadamente, sendo útil para correção de curso sem anular o turno.

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();
}

Como a direção funciona internamente

  1. A mensagem é adicionada à fila do ImmediatePromptProcessor runtime
  2. Antes da próxima solicitação ao LLM durante o turno atual, o processador injeta a mensagem na conversa
  3. O agente vê a mensagem de direção como uma nova mensagem de usuário e ajusta sua resposta
  4. Se a curva for concluída antes que a mensagem de direção seja processada, ela será movida automaticamente para a fila regular para a próxima curva

Observação

As mensagens de direção são o melhor esforço na curva atual. Se o agente já tiver se comprometido com uma chamada da ferramenta, a orientação entrará em vigor após a conclusão dessa chamada, mas ainda dentro da mesma etapa.

Fila (modo de enfileiramento)

O enfileiramento armazena em buffer as mensagens para serem processadas sequencialmente após a conclusão do turno atual. Cada mensagem enfileirada inicia seu próprio turno completo. Esse é o modo padrão, se você omitir mode, o SDK usará "enqueue".

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
}

Como a fila funciona internamente

  1. A mensagem é adicionada ao itemQueue da sessão como um QueuedItem
  2. Quando o turno atual terminar e a sessão ficar ociosa, processQueuedItems() será executado
  3. Os itens são retirados da fila na ordem FIFO—cada mensagem dispara uma interação agêntica completa
  4. Se uma mensagem de direção estava pendente quando a curva terminou, ela é movida para a frente da fila
  5. O processamento continua até que a fila esteja vazia e, em seguida, a sessão emitirá um evento ocioso

Combinando direção e fila

Você pode usar os dois padrões juntos em uma única sessão. O controle de direção afeta o movimento atual enquanto as mensagens enfileiradas esperam sua vez.

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",
)

Escolhendo entre direção e fila

ScenarioPatternPor que
O agente está indo pelo caminho errado
DirecçãoRedireciona a curva atual sem perder o progresso
Você pensou em algo que o agente também deveria fazer
EnfileiramentoNão interrompe o trabalho atual; executa em seguida
O agente está prestes a cometer um erro
DirecçãoIntervém antes que o erro seja cometido
Você deseja encadear várias tarefas
EnfileiramentoA ordenação FIFO garante uma execução previsível
Você deseja adicionar contexto à tarefa atual
DirecçãoO Agente incorpora-o ao seu raciocínio atual
Você deseja enviar em lote solicitações não relacionadas
EnfileiramentoCada um obtém seu próprio turno completo com contexto limpo

Criando uma interface do usuário com direção e fila

Aqui está um padrão para criar uma interface do usuário interativa que dá suporte a ambos os modos:

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
    }
}

Referência de API

Opções de Mensagem

LinguagemCampoTipoDefaultDescription
Node.jsmode"enqueue" | "immediate""enqueue"Modo de entrega de mensagens
PythonmodeLiteral["enqueue", "immediate"]"enqueue"Modo de entrega de mensagens
GoModestring"enqueue"Modo de entrega de mensagens
.NETModestring?"enqueue"Modo de entrega de mensagens

Modos de entrega

ModoEfeitoDurante o turno ativoDurante a inatividade
"enqueue"Fila para a próxima curvaEsperas na fila FIFOInicia uma nova curva imediatamente
"immediate"Injetar no turno atualInjetado antes da próxima chamada LLMInicia uma nova curva imediatamente

Observação

Quando a sessão está ociosa (não processando), ambos os modos se comportam de forma idêntica– a mensagem inicia um novo turno imediatamente.

Práticas recomendadas

  1. Definir como padrão o enfileiramento — Usar "enqueue" (ou omitir mode) para a maioria das mensagens. É previsível e não corre o risco de interromper o trabalho em andamento.

  2. Reserve o direcionamento exclusivamente para correções — use "immediate" quando o agente estiver fazendo algo errado ativamente e for necessário redirecioná-lo antes que ele avance ainda mais.

  3. Mantenha as mensagens de direção concisas: o agente precisa entender rapidamente a correção do curso. Mensagens de direção longas e complexas podem confundir o contexto atual.

  4. Não direcione demais— várias mensagens de direção rápidas podem prejudicar a qualidade da curva. Se você precisar alterar significativamente a direção, considere anular a curva e iniciar novamente.

  5. Mostrar o estado da fila na interface do usuário — exiba o número de mensagens enfileiradas para que os usuários saibam o que está pendente. Monitore eventos de inatividade para limpar a tela.

  6. Manipular o fallback de direção para fila — se uma mensagem de direção chegar após a conclusão da curva, ela será movida automaticamente para a fila. Crie sua interface do usuário para refletir essa transição.

Consulte também