Types de messages et convertToLlm
messages.ts ajoute quatre types de messages personnalisés à l'AgentMessage de pi-agent-core : bashExecution, custom, branchSummary, compactionSummary. L'Agent sous-jacent ne reconnaît que user/assistant/toolResult, et convertToLlm traduit ces quatre types personnalisés en Message[], en filtrant les résultats d'exécution bash marqués excludeFromContext. L'extension par fusion de déclarations (declaration merging) se fait via l'interface CustomAgentMessages, alignant couche de types et couche d'exécution.
Responsabilités
- Extension de types : utilise
declare modulepour ajouter quatre rôles à l'interfaceCustomAgentMessages, voirpackages/coding-agent/src/core/messages.ts:69-77. - Messages d'exécution bash : résultats des commandes
!, aveccommand,output,exitCode,cancelled,truncated,fullOutputPath, etexcludeFromContextoptionnel (correspond au préfixe!!). Voirpackages/coding-agent/src/core/messages.ts:29-40. - Messages custom : messages injectés via
sendMessagepar les extensions,customTypedistingue les types,displaycontrôle l'affichage UI,detailsest une donnée structurée optionnelle. Voirpackages/coding-agent/src/core/messages.ts:46-53. - Branch / compaction summary : résumé de branche inséré quand un fork revient à la branche principale, résumé de compaction inséré après compression, tous deux enveloppés dans des balises
<summary>. Voirpackages/coding-agent/src/core/messages.ts:55-67. - Fonctions factory :
createBranchSummaryMessage/createCompactionSummaryMessage/createCustomMessageconvertissent un timestamp chaîne en millisecondes numériques. Voirpackages/coding-agent/src/core/messages.ts:100-138. - convertToLlm : convertit les messages personnalisés en
Message[]; bash utilisebashExecutionToTextpour produire un message user, branch/compaction summary sont enveloppés dans<summary>, et les bashexcludeFromContextretournent undefined pour être filtrés. Voirpackages/coding-agent/src/core/messages.ts:148-195.
Motifs de conception
Pourquoi ne pas réutiliser directement les messages user ? Parce que la couche UI a besoin de distinguer « c'est une sortie d'exécution bash » d'« c'est une entrée utilisateur » : le rendu, la possibilité de repli et la réémission diffèrent. Mais le LLM n'a besoin de voir que du texte — convertToLlm aplatit tous les types personnalisés en messages user avant l'envoi au provider, le modèle n'a aucune conscience de l'existence des types custom. On préserve ainsi la richesse sémantique pour l'UI sans polluer le contexte du modèle.
bashExecutionToText formate la sortie bash en bloc de code Markdown, avec préfixe Ran \command`et suffixe contenant le code de sortie, pour que le LLM voie un format proche de ce que l'utilisateur voit dans l'UI. Les commandes bash préfixées!!sont totalement retirées du contexte LLM viaexcludeFromContext: true` — c'est l'utilisateur qui choisit activement « cette exécution, le modèle ne la voit pas », typiquement pour opérations sensibles ou sorties bruitées.
branchSummary et compactionSummary sont enveloppés dans des balises XML <summary>, un format recommandé par Anthropic : le modèle a tendance à traiter le contenu de la balise comme une unité complète plutôt que de le disperser en paragraphes.
Fichiers clés
packages/coding-agent/src/core/messages.ts:11-24— constantesCOMPACTION_SUMMARY_PREFIX/SUFFIXetBRANCH_SUMMARY_PREFIX/SUFFIX.packages/coding-agent/src/core/messages.ts:29-40— interfaceBashExecutionMessage.packages/coding-agent/src/core/messages.ts:46-53— interfaceCustomMessage<T>.packages/coding-agent/src/core/messages.ts:55-67—BranchSummaryMessageetCompactionSummaryMessage, ce dernier stockant aussitokensBeforeà des fins de diagnostic.packages/coding-agent/src/core/messages.ts:69-77— fusion de déclarationsdeclare module, étendantCustomAgentMessages.packages/coding-agent/src/core/messages.ts:82-98—bashExecutionToText, formate la sortie bash en texte LLM-friendly.packages/coding-agent/src/core/messages.ts:100-138— trois fonctions factorycreate*.packages/coding-agent/src/core/messages.ts:148-195—convertToLlm, motif switch + filter.
convertToLlm utilise un switch + vérification d'exhaustivité via never : oublier de traiter un nouveau type provoque une erreur de compilation :
// packages/coding-agent/src/core/messages.ts:148-195
export function convertToLlm(messages: AgentMessage[]): Message[] {
return messages
.map((m): Message | undefined => {
switch (m.role) {
case "bashExecution":
if (m.excludeFromContext) {
return undefined;
}
return {
role: "user",
content: [{ type: "text", text: bashExecutionToText(m) }],
timestamp: m.timestamp,
};
case "custom": {
const content = typeof m.content === "string" ? [{ type: "text" as const, text: m.content }] : m.content;
return { role: "user", content, timestamp: m.timestamp };
}
// ... branchSummary / compactionSummary ...
case "user":
case "assistant":
case "toolResult":
return m;
default:
const _exhaustiveCheck: never = m;
return undefined;
}
})
.filter((m) => m !== undefined);
}bashExecutionToText enveloppe le résultat d'exécution dans un bloc de code Markdown, avec code de sortie et indication de tronquage :
// packages/coding-agent/src/core/messages.ts:82-98
export function bashExecutionToText(msg: BashExecutionMessage): string {
let text = `Ran \`${msg.command}\`\n`;
if (msg.output) {
text += `\`\`\`\n${msg.output}\n\`\`\``;
} else {
text += "(no output)";
}
if (msg.cancelled) {
text += "\n\n(command cancelled)";
} else if (msg.exitCode !== null && msg.exitCode !== undefined && msg.exitCode !== 0) {
text += `\n\nCommand exited with code ${msg.exitCode}`;
}
if (msg.truncated && msg.fullOutputPath) {
text += `\n\n[Output truncated. Full output: ${msg.fullOutputPath}]`;
}
return text;
}Flux de données
Le chemin d'un message jusqu'au LLM :
Limites et cas d'échec
- excludeFromContext : les résultats d'exécution bash préfixés
!!sont totalement filtrés dansconvertToLlm, le modèle ne les voit pas, mais l'UI les affiche toujours. Voirpackages/coding-agent/src/core/messages.ts:152-156. - Deux formes de custom content :
CustomMessage.contentpeut être une string ouArray<TextContent | ImageContent>; quand c'est une string, elle est convertie en tableau à un seul TextContent. Voirpackages/coding-agent/src/core/messages.ts:162-168. - Conversion string vers nombre du timestamp : les trois fonctions
create*utilisentnew Date(timestamp).getTime(); si on passe un timestamp déjà numérique, on obtient NaN — l'appelant doit garantir une chaîne ISO. Voirpackages/coding-agent/src/core/messages.ts:105-106. - Couche blockImages :
createAgentSessionenveloppeconvertToLlmdansconvertToLlmWithBlockImages, qui lit dynamiquement les settings pour remplacer les images par du texte placeholder. Voir la section des limites dans assemblage createAgentSession. - Même fonction pour la compaction :
transformToLlmde l'AgentetgenerateSummaryde la compaction utilisent toutes deuxconvertToLlm, garantissant que le contexte vu pendant la compaction est identique à celui envoyé au provider.
Synthèse
messages.ts utilise la fusion de déclarations TypeScript pour ajouter quatre types personnalisés à AgentMessage, et convertToLlm les aplatit en messages user avant l'envoi au provider, tandis que la couche UI conserve les types d'origine pour un rendu différencié. À l'assemblage, cette fonction est enveloppée par createAgentSession d'une couche de filtrage blockImages, voir assemblage createAgentSession ; les détails de CompactionSummaryMessage produits par le flux de compaction sont dans le répertoire compaction.