Aller au contenu
English

Permettre à l’agent de poser des questions

Suspendez une tâche pour obtenir une réponse humaine et poursuivez la conversation enregistrée.

Utilisez une tâche interactive si l’agent a besoin d’une information humaine pour poursuivre. Utilisez une tâche d’approbation si votre workflow attend une autorisation. Ces deux pauses ont des entrées et des règles de reprise différentes.

Tâche interactiveGate d’approbation
QuestionÉcrite par l’agent, adaptée aux réponses précédentesLe prompt fixe du gate
RéponseTexte libre, ou l’un des choices de l’agentapprove ou reject
Ce qu’elle reprendLa conversation de l’agent, dans un nouveau tourLes tâches qui dépendent du gate
Soumise avecstart({ answers })start({ decisions })
Preuve signéeNonFacultative, avec authentication: "signed"
DéfinitiondefineInteractiveAgentTask()defineApprovalTask(), definePauseTask()

La tâche exige un checkpoint : il conserve les questions et les réponses d’un processus à l’autre.

import { defineInteractiveAgentTask } from "@elie-laloum/outpost";
import { repository, coder, sandboxProvider } from "./outpost.config.ts";

export const clarify = defineInteractiveAgentTask({
  key: "clarify",
  repository,
  agent: coder,
  sandboxProvider,
  brief:
    'Define the application with its owner, then complete with {"summary": string, "features": string[]}.',
  actors: ["owner"],
});
import {
  createWorkflowCheckpointStore,
  createLocalTransport,
} from "@elie-laloum/outpost";

export const store = createWorkflowCheckpointStore({
  transporter: createLocalTransport({ directory: ".outpost/storage" }),
});
import { reportValue } from "./reporter.ts";
import { defineWorkflow } from "@elie-laloum/outpost";
import { clarify } from "./clarify.ts";
import { store } from "./question-store.ts";

export const workflow = defineWorkflow("discovery", [clarify]);
export const checkpoint = { store, runId: "discovery-42", version: "1" };
export const result = await workflow.start({ checkpoint });
reportValue(result.status, result.inputRequests[0]?.question);
// Example output: waiting-input What should the new endpoint return?

Le script affiche waiting-input et la première question de l’agent. Outpost ajoute lui-même le protocole de question à votre brief : le brief décrit seulement l’objectif et la forme du JSON final.

Référence API : InteractiveAgentTaskOptions.

Codex, Claude Code, Copilot CLI, Kimi Code et le harness intégré sont acceptés. Antigravity et un harness créé avec conversations: false sont refusés dès la définition de la tâche : voir Conversations.

Glissez pour vous déplacer · Ctrl + molette pour zoomer
100 %
  • TourL’agent travaille dans une sandbox neuve.
    1. ExécutionIl poursuit sa conversation avec le brief ou la dernière réponse. sandbox
    2. FermetureOutpost enregistre la conversation et ferme la sandbox. host
    (Étapes)
    • → Question : puis
  • QuestionL’exécution s’arrête sur waiting-input.
    1. EnregistrementLe checkpoint conserve la question ; les tâches dépendantes attendent. inputRequests
    (Étapes)
    • → Réponse : puis
  • RéponseVotre application la soumet.
    1. ValidationOutpost vérifie et enregistre la réponse, puis lance le tour suivant. start({ answers })
    (Étapes)
    • → Sortie : puis
  • SortieL’agent termine avec du JSON au lieu de poser une question.
    1. ConservationLe checkpoint conserve la sortie. result.value()
    (Étapes)

result.inputRequests liste toutes les questions en attente. Plusieurs tâches interactives indépendantes peuvent attendre en même temps.

Référence API : WorkflowInputRequest.

Relancez le même workflow avec le même checkpoint et une entrée answers par demande.

import type { WorkflowInputRequest } from "@elie-laloum/outpost";

export function answerValue(
  request: WorkflowInputRequest,
  actor: string,
  value: string,
) {
  return {
    executionId: request.executionId,
    key: request.key,
    requestId: request.id,
    actor,
    value,
  };
}
import type {
  Workflow,
  WorkflowCheckpointOptions,
  WorkflowInputRequest,
} from "@elie-laloum/outpost";
import { answerValue } from "./answer-value.ts";

export async function answer(
  workflow: Workflow,
  checkpoint: WorkflowCheckpointOptions,
  request: WorkflowInputRequest,
  actor: string,
  value: string,
) {
  return workflow.start({
    checkpoint,
    answers: [answerValue(request, actor, value)],
  });
}

start() exécute le tour suivant et rend la main à la question suivante ou à la fin de la tâche. Sans answers, il renvoie les questions en attente sans appeler le modèle.

Outpost vérifie toutes les réponses avant d’en appliquer une seule. Il refuse un requestId périmé, un acteur absent de actors, une autre exécution, une deuxième réponse pour la même tâche et, quand allowFreeText vaut false, une valeur hors de choices.

Lisez le résultat du dialogue avec result.value(clarify).

Référence API : InteractiveAgentResult.

result.usage cumule les tentatives et les tokens de tous les tours, réparations comprises. unwrap() lève une erreur tant que l’exécution attend. Dans un workflow qui contient aussi des étapes d’approbation, waiting-input l’emporte sur paused, et un échec ou une annulation l’emporte sur les deux.

Chaque tour ouvre une sandbox et la ferme avant la publication de la question. Les fichiers du worktree passent d’un tour à l’autre, commités ou non ; le répertoire personnel de la sandbox et les processus en cours, non.

Outpost n’intègre, ne pousse ni ne supprime jamais le worktree. Relisez branch et fusionnez-la vous-même (Dépôt et branche), puis nettoyez-la avec Rétention et nettoyage.

Le dépôt, le worktree et le stockage des conversations doivent rester aux mêmes chemins pour le processus suivant. Un worktree déplacé échoue avec Interactive workspace moved; recover it explicitly, et une branche changée avec Interactive workspace branch changed; recover it explicitly.

Un arrêt brutal pendant un tour laisse la tâche inachevée, et le start() suivant refuse de la rejouer. Autorisez le rejeu avec checkpoint: { ...checkpoint, resume: "retry-incomplete" }.

Le tour repart de la dernière conversation et de la dernière réponse enregistrées ; une sortie déjà terminée est réutilisée sans appeler le modèle. Les effets partiels du tour interrompu peuvent se répéter. Exécutions durables décrit le rejeu et la récupération de la propriété du checkpoint.

defineTask() avec interaction suspend n’importe quelle tâche sur une question. defineInteractiveAgentTask() repose sur ce mécanisme.

import { defineTask } from "@elie-laloum/outpost";

const region = defineTask({
  key: "region",
  interaction: { identity: "region-v1", actors: ["owner"] },
  perform: (context) => {
    const interaction = context.interaction;
    if (!interaction) throw new Error("Run with a checkpoint");
    const answer = interaction.answer;
    if (!answer)
      return interaction.suspend(
        { question: "Deploy to which region?", choices: ["eu", "us"] },
        { step: "region" },
      );
    return { region: answer.value };
  },
});

perform repart du début après chaque réponse. Lisez interaction.state pour sauter le travail déjà fait, et save(state) pour enregistrer l’avancement ; les deux ne contiennent que du JSON.

  • Une question au dernier des maxTurns fait échouer la tâche au lieu d’attendre.
  • Les questions n’expirent pas et les réponses ne sont pas signées.
  • Une annulation arrête le tour en cours ; une question déjà enregistrée reste en attente.
  • Changer l’agent, le modèle, le brief, le dépôt, le fournisseur, les acteurs ou maxTurns rend le checkpoint enregistré incompatible : démarrez un nouveau runId.

Un scénario complet, avec une approbation, des tests rouges et du code relu : Construire un workflow de développement.

API : defineInteractiveAgentTask · InteractiveAgentTaskOptions · InteractiveAgentResult · WorkflowInputRequest · WorkflowAnswer · TaskInteractionContext