Skip to main content

Mode flotte

Utilisez le mode Fleet pour répartir le travail entre plusieurs sous-agents et combiner leurs résultats dans une session principale.

Quand utiliser le mode flotte

Le mode flotte est utile lorsque le travail peut être décomposé avant l’exécution et que chaque unité peut s’exécuter sans attendre les autres.

Les bonnes ajustements sont les suivantes :

  • Refactorisations multi-fichiers où chaque worker possède un fichier, un package ou un KIT SDK de langage.
  • Révisions par lot où chaque intervenant examine une différence, un module ou un groupe d’alertes distinct.
  • Recherche parallèle sur les dépôts, services ou domaines de fonctionnalités indépendants.
  • Mises à jour de la documentation où chaque contributeur est responsable d’une page ou d’une rubrique.
  • Tâches de migration où chaque worker peut valider sa propre tranche et rapporter.

Évitez le mode flotte pour :

  • Tâches séquentielles où l’étape 2 a besoin de la sortie concrète de l’étape 1.
  • Modifications fortement couplées où les collaborateurs se disputeraient les mêmes fichiers.
  • Les petites tâches qu’un sous-agent synchrone ou l’agent parent peut terminer rapidement.
  • Les tâches qui nécessitent un raisonnement partagé continu plutôt que la propriété claire.

Le mode Fleet fonctionne mieux lorsque la session parente peut créer des unités de travail claires, attribuer un responsable à chaque unité et définir ce que chaque agent doit renvoyer.

Démarrage du mode flotte

Le Kit de développement logiciel (SDK) expose le mode flotte via l’espace de noms RPC de session dans plusieurs langues. La liaison est expérimentale dans l’interface RPC générée ; verrouillez à la fois le SDK et le runtime de l’interface en ligne de commande Copilot si votre application en dépend.

À partir d’une session

La méthode filaire est session.fleet.start. Le facultatif prompt est combiné aux instructions d’orchestration de flotte du runtime.

TypeScript
const result = await session.rpc.fleet.start({
    prompt: "Refactor each SDK package independently, then summarize the changes.",
});

if (result.started) {
    console.log("Fleet mode started");
}
Python
from copilot.generated.rpc import FleetStartRequest

result = await session.rpc.fleet.start(
    FleetStartRequest(
        prompt="Review each service independently, then summarize the risks."
    )
)

if result.started:
    print("Fleet mode started")
Go
package main

import (
    "context"
    "fmt"

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

func main() {
    ctx := context.Background()
    client := copilot.NewClient(nil)
    session, err := client.CreateSession(ctx, &copilot.SessionConfig{})
    if err != nil {
        return
    }

    prompt := "Update each package independently, then report validation results."
    result, err := session.RPC.Fleet.Start(ctx, &rpc.FleetStartRequest{
        Prompt: &prompt,
    })
    if err != nil {
        return
    }
    if result.Started {
        fmt.Println("Fleet mode started")
    }
}
prompt := "Update each package independently, then report validation results."
result, err := session.RPC.Fleet.Start(ctx, &rpc.FleetStartRequest{
    Prompt: &prompt,
})
if err != nil {
    return err
}
if result.Started {
    fmt.Println("Fleet mode started")
}
.NET
using GitHub.Copilot;

await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig());

var result = await session.Rpc.Fleet.StartAsync(
    "Audit each project independently, then summarize the findings.");

if (result.Started)
{
    Console.WriteLine("Fleet mode started");
}
var result = await session.Rpc.Fleet.StartAsync(
    "Audit each project independently, then summarize the findings.");

if (result.Started)
{
    Console.WriteLine("Fleet mode started");
}
Rust
use github_copilot_sdk::generated::api_types::FleetStartRequest;

let result = session
    .rpc()
    .fleet()
    .start(FleetStartRequest {
        prompt: Some("Research each crate independently, then summarize the plan.".into()),
    })
    .await?;

if result.started {
    println!("Fleet mode started");
}

Les liaisons typées natives pour le mode flotte ont été vérifiées dans Node.js/TypeScript, Python, Go, .NET et Rust. Aucune liaison pour Java n’a été trouvée dans java/src/main/java sur cette branche ; les exemples Java ne sont donc pas inclus tant que cette interface n’est pas disponible.

À partir du mode plan

Les interfaces utilisateur du mode Plan peuvent lancer le déploiement de la flotte en renvoyant l’action de sortie autopilot_fleet. Les types d’événements de session générés le décrivent comme suit :

type PlanModeExitAction =
  | "exit_only"
  | "interactive"
  | "autopilot"
  /** Exit plan mode and continue with parallel autonomous workers. */
  | "autopilot_fleet";

Utilisez cette option lorsqu’un utilisateur approuve un plan qui contient déjà des éléments de travail indépendants. Utiliser autopilot pour un agent autonome unique et interactive lorsque l’utilisateur doit rester dans le processus.

Comment les sous-agents se coordonnent

Le mode flotte s’appuie sur un état de coordination explicite au lieu de la mémoire partagée implicite. L’agent parent décompose le travail en todos, chaque sous-agent possède un todo et l’orchestrateur répartit les workers dont les dépendances sont déjà terminées.

Le schéma canonique est :

CREATE TABLE todos (
    id TEXT PRIMARY KEY,
    title TEXT NOT NULL,
    description TEXT,
    status TEXT DEFAULT 'pending'
);

CREATE TABLE todo_deps (
    todo_id TEXT,
    depends_on TEXT,
    PRIMARY KEY (todo_id, depends_on)
);

Chaque tâche passe par une petite machine à états :

pending -> in_progress -> done
                       \-> blocked

Un sous-agent doit :

  1. Revendiquer exactement un todo prêt à l’être en définissant status = 'in_progress'.
  2. Travaillez uniquement sur le périmètre de cette tâche.
  3. Stocker le résultat dans la conversation ou dans le résultat de la tâche correspondante.
  4. Définissez status = 'done' une fois terminé.
  5. Définissez status = 'blocked' quand il ne peut pas continuer et incluez la raison.

L’orchestrateur peut identifier les tâches pour lesquelles les dépendances sont satisfaites à l’aide d’une requête telle que :

SELECT t.*
FROM todos t
WHERE t.status = 'pending'
  AND NOT EXISTS (
      SELECT 1
      FROM todo_deps td
      JOIN todos dep ON td.depends_on = dep.id
      WHERE td.todo_id = t.id
        AND dep.status != 'done'
  );

Ce modèle attribue à chaque processus un responsable clairement identifié et permet à la session parente de déterminer ce qui est prêt, en cours d’exécution, terminé ou bloqué.

Hooks de cycle de vie

Le mode flotte appelle des sous-agents via le mécanisme de tâche du runtime. Le runtime émet l’activité des hooks pour les appels d’outils de sous-agent : le journal des modifications de runtime 1.0.52 indique que preToolUse, postToolUse, subagentStart et subagentStop se déclenchent correctement pour les appels d’outils de sous-agent.

Aucune fonction de rappel de hook du SDK dédiée pour subagentStart ou subagentStop n’a été trouvée dans l’API publique du SDK sur cette branche. Les consommateurs du Kit de développement logiciel (SDK) peuvent observer l’activité de sous-agent via le flux d’événements de session générique, qui inclut des événements tels que subagent.started, , subagent.completed, subagent.failed``subagent.selected, et subagent.deselected.

TypeScript
session.on((event) => {
    if (event.type === "subagent.started") {
        console.log(`Started ${event.data.agentDisplayName}`);
    }

    if (event.type === "subagent.completed") {
        console.log(`Completed ${event.data.agentDisplayName}`);
    }
});
Python
import asyncio
from copilot import CopilotClient
from copilot.session import PermissionHandler

async def main():
    client = CopilotClient()
    await client.start()
    session = await client.create_session(
        on_permission_request=PermissionHandler.approve_all,
    )

    def handle_event(event):
        if event.type == "subagent.started":
            print(f"Started {event.data.agent_display_name}")
        elif event.type == "subagent.completed":
            print(f"Completed {event.data.agent_display_name}")

    unsubscribe = session.on(handle_event)

asyncio.run(main())
def handle_event(event):
    if event.type == "subagent.started":
        print(f"Started {event.data.agent_display_name}")
    elif event.type == "subagent.completed":
        print(f"Completed {event.data.agent_display_name}")

unsubscribe = session.on(handle_event)

Pour connaître la configuration de hook déjà exposée au niveau de la couche sdk, consultez Utilisation de crochets. Pour connaître les charges utiles des événements de sous-agent, consultez Agents personnalisés et orchestration de sous-agents.

Sous-agents de plug-in

Le runtime peut charger des plug-ins avec --plugin-dir. Les plug-ins chargés de cette façon peuvent enregistrer leurs agents comme types de sous-agents disponibles task(agent_type=...) en mode prompt, ce qui signifie que le mode flotte peut répartir les tâches vers ces types de workers fournis par les plug-ins.

Il s’agit actuellement d’un modèle de configuration au niveau du runtime plutôt qu’une API d’inscription au niveau du SDK documentée. Configurez le runtime CLI Copilot avec le répertoire du plug-in, puis connectez le client sdk à ce runtime. Les helpers natifs du KIT de développement logiciel (SDK) pour l’inscription des types de sous-agent de plug-in peuvent être ajoutés ultérieurement.

Conceptuellement, un prompt de flotte peut ensuite demander un type spécifique de worker :

Use task(agent_type="security-review") for each independent package.
Run the workers in parallel and summarize only high-confidence findings.

Conservez les types de sous-agents fournis par le plug-in de manière étroite et descriptive afin que l’orchestrateur puisse les choisir de manière fiable.

Bonnes pratiques

  • Décomposez le travail en unités indépendantes avant de démarrer le mode flotte.
  • Réduire les dépendances entre les tâches ; les dépendances réduisent le parallélisme.
  • Donnez à chacun un ID durable, un titre clair et une description complète.
  • Faites en sorte que chaque sous-agent soit responsable d’exactement une tâche à la fois.
  • Utilisez des sous-agents en arrière-plan pour un travail réellement parallèle.
  • Utilisez des appels de sous-agent synchrones pour les étapes sérialisées ou les portes de validation.
  • Fournissez à chaque sous-agent un contexte complet ; les sous-agents sont sans état entre les appels.
  • Incluez les chemins d’accès, les commandes, les sorties attendues et les contraintes dans chaque invite de travail.
  • Ne lancez pas un seul sous-agent en arrière-plan ; préférez un appel synchrone ou exécutez plusieurs processus de travail en parallèle.
  • Évitez d’affecter des fichiers qui se chevauchent à différents workers, sauf si l’agent parent rapprochera explicitement les conflits.
  • Exiger que chaque intervenant indique ce qu’il a modifié, comment il a validé ce changement et ce qui reste bloqué.
  • Demandez à l’agent parent de vérifier le résultat combiné une fois que les agents de travail ont terminé.

Limitations et questions ouvertes

  • Le mode Fleet est exposé via des bindings RPC de session générés et est indiqué comme expérimental dans plusieurs SDK.
  • Le modèle SQL todos est le modèle de coordination canonique dans le guide d’exécution, mais la question de savoir s’il constitue un contrat d’extensibilité stable pour les utilisateurs du SDK reste ouverte.
  • subagentStart et subagentStop sont des noms de hook d’exécution ; cette branche expose le cycle de vie du sous-agent aux consommateurs du SDK via le flux d’événements de session générique, et non les rappels de hook dédiés.
  • L’enregistrement du sous-agent du plug-in est configuré dans la couche d’exécution via --plugin-dir ; aucun outil d’aide à l’enregistrement du plug-in au niveau du SDK n’a été identifié sur cette branche.
  • Les liaisons natives typées Java pour session.fleet.start n’ont pas été trouvées dans le code source du SDK Java sur cette branche.
  • Le mode flotte ne supprime pas la nécessité de passer en revue l’agent parent. Les travailleurs parallèles peuvent produire des hypothèses incohérentes que l’orchestrateur doit rapprocher.

Voir également :