Claude Fable 5 est le modèle le plus capable d'Anthropic pour le travail autonome à long terme. Lancé le 9 juin 2026 — et pleinement rétabli après une suspension temporaire liée aux contrôles des exportations le 1er juillet 2026 — il apporte une fenêtre de contexte d'un million de tokens, jusqu'à 128 000 tokens en sortie par réponse, et une réflexion étendue native à l'API Messages. Avec le passage à la facturation à l'usage le 7 juillet 2026, le moment n'a jamais été aussi propice pour commencer à développer avec ce modèle.
Dans ce tutoriel, vous allez construire un outil CLI TypeScript qui effectue une revue de code complète de n'importe quel répertoire de projet. L'agent lit les fichiers à l'aide d'outils personnalisés, applique la réflexion étendue pour l'analyse de sécurité et d'architecture, et utilise le cache de prompts pour réduire les coûts d'API de 90%. C'est le pattern de "délégation complète de tâche" pour lequel Fable 5 a été conçu.
Prérequis
- Node.js 20+ — vérifiez avec
node --version - Maîtrise de TypeScript et de
async/await - Une clé Anthropic API — générez-la sur console.anthropic.com
- Un éditeur de code (VS Code recommandé)
Aucun matériel GPU requis. Toute l'inférence s'exécute sur l'API hébergée d'Anthropic.
Ce que vous allez construire
À la fin de ce tutoriel, vous disposerez d'une commande CLI :
npx tsx review-agent.ts ./my-projectElle lance un agent Fable 5 qui explore votre base de code de manière autonome avec des outils de système de fichiers, applique la réflexion étendue pour détecter les vulnérabilités de sécurité, et diffuse un rapport structuré avec les sections Critique, Haute priorité, Priorité moyenne et Recommandations.
Comprendre Claude Fable 5
Un aperçu rapide du modèle avant d'écrire du code.
En quoi Fable 5 diffère-t-il de Sonnet 5 ?
| Caractéristique | Claude Sonnet 5 | Claude Fable 5 |
|---|---|---|
| Fenêtre de contexte | 200 000 tokens | 1 million de tokens |
| Sortie maximale | 64 000 tokens | 128 000 tokens |
| Idéal pour | Réponses rapides et itératives | Tâches autonomes multi-étapes |
| Prix entrée | 3 $ / MTok | 10 $ / MTok |
| Prix sortie | 15 $ / MTok | 50 $ / MTok |
| Entrée en cache | 0,30 $ / MTok | 1 $ / MTok |
Utilisez Sonnet 5 pour les fonctionnalités interactives. Utilisez Fable 5 quand vous avez besoin d'un agent qui planifie sur de nombreuses étapes, délègue des sous-tâches, vérifie son propre travail et produit un résultat cohérent sur des dizaines d'appels d'outils.
Étape 1 : Configuration du projet
mkdir fable5-reviewer && cd fable5-reviewer
npm init -y
npm install @anthropic-ai/sdk dotenv
npm install -D typescript tsx @types/nodeCréez tsconfig.json :
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true
}
}Créez .env :
ANTHROPIC_API_KEY=sk-ant-...
Ne committez jamais ce fichier — ajoutez-le immédiatement à .gitignore.
Étape 2 : Vérifier le streaming avec Fable 5
Les appels non-streaming à Fable 5 peuvent prendre plus de 60 secondes sur des prompts complexes. Utilisez toujours le streaming. Voici un test minimal :
// stream-test.ts
import Anthropic from '@anthropic-ai/sdk';
import 'dotenv/config';
const client = new Anthropic();
async function main(): Promise<void> {
const stream = client.messages.stream({
model: 'claude-fable-5',
max_tokens: 512,
messages: [
{
role: 'user',
content: 'Listez 5 choses à vérifier dans un audit de sécurité TypeScript. Soyez bref.',
},
],
});
for await (const chunk of stream) {
if (
chunk.type === 'content_block_delta' &&
chunk.delta.type === 'text_delta'
) {
process.stdout.write(chunk.delta.text);
}
}
const final = await stream.finalMessage();
console.log(
`\n\nTokens : ${final.usage.input_tokens} entrée / ${final.usage.output_tokens} sortie`
);
}
main();Lancez-le :
npx tsx stream-test.tsVous devriez voir la liste s'afficher token par token. Si vous obtenez model_not_available, vérifiez que l'accès est activé sur votre compte console.anthropic.com.
Étape 3 : Définir les outils de système de fichiers
Les outils permettent à Fable 5 de lire votre projet. Définissez-en trois : list_directory, read_file et search_pattern.
// tools.ts
import { readFileSync, readdirSync, statSync } from 'fs';
import { join, extname } from 'path';
import type Anthropic from '@anthropic-ai/sdk';
const ALLOWED_EXTENSIONS = new Set([
'.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
'.json', '.md', '.yaml', '.yml', '.toml', '.env.example',
]);
export const toolDefinitions: Anthropic.Tool[] = [
{
name: 'list_directory',
description: 'Lister les fichiers et répertoires à un chemin donné.',
input_schema: {
type: 'object' as const,
properties: {
path: { type: 'string', description: 'Chemin du répertoire à lister' },
recursive: { type: 'boolean', description: 'Lister récursivement' },
},
required: ['path'],
},
},
{
name: 'read_file',
description: 'Lire le contenu texte d\'un fichier source.',
input_schema: {
type: 'object' as const,
properties: {
path: { type: 'string', description: 'Chemin absolu ou relatif du fichier' },
},
required: ['path'],
},
},
{
name: 'search_pattern',
description: 'Rechercher un pattern regex dans tous les fichiers source d\'un répertoire. Retourne les lignes correspondantes avec le chemin de fichier et le numéro de ligne.',
input_schema: {
type: 'object' as const,
properties: {
pattern: { type: 'string', description: 'Pattern regex à rechercher' },
directory: { type: 'string', description: 'Répertoire racine de recherche' },
maxResults: {
type: 'number',
description: 'Nombre maximum de résultats (défaut 50)',
},
},
required: ['pattern', 'directory'],
},
},
];
function walkDir(dir: string, recursive: boolean): string[] {
const results: string[] = [];
for (const name of readdirSync(dir)) {
if (name.startsWith('.') || name === 'node_modules' || name === 'dist') continue;
const full = join(dir, name);
const stat = statSync(full);
if (stat.isDirectory()) {
results.push(`${full}/`);
if (recursive) results.push(...walkDir(full, true));
} else {
results.push(full);
}
}
return results;
}
function grepFiles(pattern: string, dir: string, maxResults: number): string[] {
const regex = new RegExp(pattern, 'gi');
const matches: string[] = [];
const files = walkDir(dir, true).filter(
(f) => !f.endsWith('/') && ALLOWED_EXTENSIONS.has(extname(f))
);
for (const file of files) {
if (matches.length >= maxResults) break;
try {
const lines = readFileSync(file, 'utf-8').split('\n');
for (let i = 0; i < lines.length; i++) {
if (regex.test(lines[i])) {
matches.push(`${file}:${i + 1}: ${lines[i].trim()}`);
if (matches.length >= maxResults) break;
}
}
} catch {
// ignorer les fichiers illisibles
}
}
return matches;
}
export function executeTool(
name: string,
input: Record<string, unknown>
): string {
try {
if (name === 'list_directory') {
const path = input.path as string;
const recursive = (input.recursive as boolean) ?? false;
const entries = walkDir(path, recursive);
return entries.slice(0, 300).join('\n') || '(répertoire vide)';
}
if (name === 'read_file') {
const path = input.path as string;
if (!ALLOWED_EXTENSIONS.has(extname(path))) {
return `Ignoré : extension ${extname(path)} non autorisée.`;
}
const content = readFileSync(path, 'utf-8');
return content.length > 50_000
? content.slice(0, 50_000) + '\n\n[fichier tronqué — plus de 50 000 caractères]'
: content;
}
if (name === 'search_pattern') {
const pattern = input.pattern as string;
const directory = input.directory as string;
const maxResults = (input.maxResults as number) ?? 50;
const hits = grepFiles(pattern, directory, maxResults);
return hits.length > 0 ? hits.join('\n') : 'Aucune correspondance trouvée.';
}
return `Outil inconnu : ${name}`;
} catch (err) {
return `Erreur outil : ${(err as Error).message}`;
}
}La limite de 50 000 caractères par fichier protège le budget de contexte. Même avec la fenêtre de contexte d'un million de tokens de Fable 5, un seul fichier volumineux peut consommer des dizaines de milliers de tokens inutilement.
Étape 4 : La boucle principale de l'agent
La boucle pilote Fable 5 jusqu'à ce qu'il retourne une réponse finale. À chaque tour : appelez l'API, exécutez les appels d'outils demandés, renvoyez les résultats, répétez.
// agent-loop.ts
import Anthropic from '@anthropic-ai/sdk';
import { toolDefinitions, executeTool } from './tools.js';
const client = new Anthropic();
const SYSTEM = `Vous êtes un ingénieur logiciel senior effectuant une revue de code approfondie et systématique.
Processus :
1. Appelez list_directory sur la racine du projet (recursive: true) pour comprendre la structure.
2. Lisez d'abord les fichiers de configuration clés : package.json, tsconfig.json, .eslintrc.
3. Lisez chaque fichier source principal à la suite.
4. Utilisez search_pattern pour rechercher les problèmes de sécurité courants : eval, dangerouslySetInnerHTML, construction SQL par chaînes, secrets codés en dur.
5. Après avoir lu tous les fichiers pertinents, rédigez un rapport structuré.
Format du rapport :
## Problèmes critiques
## Haute priorité
## Priorité moyenne
## Recommandations`;
export async function runReviewAgent(projectPath: string): Promise<void> {
const messages: Anthropic.MessageParam[] = [
{
role: 'user',
content: `Effectuez une revue de code complète du projet situé à : ${projectPath}
Examinez tout — sécurité, exactitude, qualité TypeScript, gestion des erreurs et architecture. Commencez par explorer la structure du projet.`,
},
];
let iteration = 0;
const maxIterations = 40;
console.log(`\nRevue de code Fable 5 — ${projectPath}\n${'─'.repeat(60)}\n`);
while (iteration < maxIterations) {
iteration++;
const response = await client.messages.create({
model: 'claude-fable-5',
max_tokens: 8192,
system: SYSTEM,
tools: toolDefinitions,
messages,
});
messages.push({ role: 'assistant', content: response.content });
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const block of response.content) {
if (block.type === 'text' && block.text) {
process.stdout.write(block.text);
} else if (block.type === 'tool_use') {
const input = block.input as Record<string, unknown>;
console.log(`\n [${block.name}] ${JSON.stringify(input).slice(0, 80)}`);
const result = executeTool(block.name, input);
toolResults.push({
type: 'tool_result',
tool_use_id: block.id,
content: result,
});
}
}
if (toolResults.length > 0) {
messages.push({ role: 'user', content: toolResults });
continue;
}
if (response.stop_reason === 'end_turn') {
console.log(`\n${'─'.repeat(60)}\nTerminé — ${iteration} itérations`);
break;
}
console.warn(`\nstop_reason inattendu : ${response.stop_reason}`);
break;
}
if (iteration >= maxIterations) {
console.warn('Nombre maximum d\'itérations atteint — la revue peut être incomplète.');
}
}Fable 5 termine généralement la revue d'un projet TypeScript de taille moyenne en 8 à 18 itérations. La limite de 40 itérations est un filet de sécurité pour les très grands monorepos.
Étape 5 : Réflexion étendue pour l'analyse de sécurité approfondie
La réflexion étendue permet à Fable 5 de raisonner en privé avant d'écrire sa réponse finale. Pour l'analyse de sécurité, c'est crucial : les chaînes de vulnérabilités nécessitent un raisonnement plus approfondi que la simple correspondance de patterns en surface. Activez-la avec le paramètre thinking :
// deep-review.ts
import Anthropic from '@anthropic-ai/sdk';
import { toolDefinitions, executeTool } from './tools.js';
const client = new Anthropic();
export async function runDeepSecurityAudit(projectPath: string): Promise<void> {
const messages: Anthropic.MessageParam[] = [
{
role: 'user',
content: `Effectuez un audit de sécurité approfondi de ${projectPath}.
Concentrez-vous sur :
- Vulnérabilités d'injection (SQL, commandes, traversée de chemin)
- Failles d'authentification et d'autorisation
- Exposition de données sensibles et secrets dans le code
- Dépendances vulnérables dans package.json
Examinez soigneusement tous les fichiers source, puis fournissez un rapport de sécurité détaillé.`,
},
];
let iteration = 0;
while (iteration < 30) {
iteration++;
const response = await client.messages.create({
model: 'claude-fable-5',
max_tokens: 16000,
tools: toolDefinitions,
messages,
thinking: {
type: 'enabled',
budget_tokens: 8000,
},
});
messages.push({ role: 'assistant', content: response.content });
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const block of response.content) {
if (block.type === 'thinking') {
console.log(`\n [réflexion — ${block.thinking.length} caractères]`);
} else if (block.type === 'text' && block.text) {
process.stdout.write(block.text);
} else if (block.type === 'tool_use') {
console.log(`\n [${block.name}]`);
const result = executeTool(
block.name,
block.input as Record<string, unknown>
);
toolResults.push({
type: 'tool_result',
tool_use_id: block.id,
content: result,
});
}
}
if (toolResults.length > 0) {
messages.push({ role: 'user', content: toolResults });
continue;
}
if (response.stop_reason === 'end_turn') break;
}
}Une valeur budget_tokens de 8000 est un bon point de départ. Pour les audits de sécurité, des valeurs entre 4000 et 16 000 sont pratiques. Les tokens de réflexion sont facturés aux tarifs d'entrée, pas de sortie.
Étape 6 : Cache de prompts — 90% d'économies
À 10 $ par million de tokens d'entrée, une session d'agent de 40 tours sur un grand projet peut accumuler des coûts significatifs — l'historique complet de la conversation est envoyé à chaque tour. Le cache de prompts stocke les blocs statiques sur les serveurs d'Anthropic pendant 5 minutes, les facturant à seulement 1 $ par million de tokens.
// cached-agent.ts
import Anthropic from '@anthropic-ai/sdk';
import { readFileSync } from 'fs';
import { toolDefinitions, executeTool } from './tools.js';
const client = new Anthropic();
export async function runCachedReview(projectPath: string): Promise<void> {
let packageJson = '(pas de package.json)';
try {
packageJson = readFileSync(`${projectPath}/package.json`, 'utf-8');
} catch { /* non trouvé */ }
const systemContent: Anthropic.TextBlockParam[] = [
{
type: 'text',
text: `Vous êtes un réviseur de sécurité et qualité de code.\n\npackage.json du projet :\n\`\`\`json\n${packageJson}\n\`\`\`\n\nRéférez-vous à ce fichier lors de l'analyse des dépendances.`,
cache_control: { type: 'ephemeral' }, // Mettre ce grand bloc en cache pendant 5 minutes
},
{
type: 'text',
text: "Utilisez les outils fournis pour lire les fichiers source. Signalez les problèmes par ordre de gravité.",
},
];
const messages: Anthropic.MessageParam[] = [
{
role: 'user',
content: `Examinez tous les fichiers TypeScript dans ${projectPath} pour détecter les problèmes de sécurité et de qualité de code.`,
},
];
let iteration = 0;
let cachedTokensSaved = 0;
while (iteration < 30) {
iteration++;
const response = await client.messages.create({
model: 'claude-fable-5',
max_tokens: 8192,
system: systemContent,
tools: toolDefinitions,
messages,
});
const usage = response.usage as Anthropic.Usage & {
cache_read_input_tokens?: number;
};
if (usage.cache_read_input_tokens) {
cachedTokensSaved += usage.cache_read_input_tokens;
}
messages.push({ role: 'assistant', content: response.content });
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const block of response.content) {
if (block.type === 'text') process.stdout.write(block.text);
else if (block.type === 'tool_use') {
const result = executeTool(
block.name,
block.input as Record<string, unknown>
);
toolResults.push({
type: 'tool_result',
tool_use_id: block.id,
content: result,
});
}
}
if (toolResults.length > 0) {
messages.push({ role: 'user', content: toolResults });
continue;
}
if (response.stop_reason === 'end_turn') {
const savedUsd = ((cachedTokensSaved * 9) / 10 / 1_000_000) * 10;
console.log(
`\n\nCache économisé ~${savedUsd.toFixed(4)} $ (${cachedTokensSaved.toLocaleString()} tokens avec 90% de remise)`
);
break;
}
}
}Le cache de prompts est le plus efficace sur les blocs qui apparaissent inchangés sur de nombreux tours consécutifs : prompts système, grandes références documentaires et fichiers de configuration partagés. La fenêtre de cache de 5 minutes couvre facilement une session d'agent complète.
Étape 7 : Le CLI d'entrée
Reliez tout dans un seul fichier exécutable :
// review-agent.ts
import 'dotenv/config';
import { runCachedReview } from './cached-agent.js';
const projectPath = process.argv[2];
if (!projectPath) {
console.error('Utilisation : npx tsx review-agent.ts <chemin>');
process.exit(1);
}
console.log('Réviseur de code Claude Fable 5');
console.log(`Chemin : ${projectPath}`);
console.log('Modèle : claude-fable-5');
console.log('Contexte: 1M tokens | Sortie max : 128k tokens\n');
runCachedReview(projectPath).catch((err) => {
console.error('\nErreur agent :', err.message);
process.exit(1);
});Lancez une revue :
npx tsx review-agent.ts ./srcFable 5 explorera la structure du répertoire, lira les fichiers un par un, recherchera les patterns de sécurité et rédigera le rapport final — généralement en 2 à 5 minutes pour un projet TypeScript de taille moyenne.
Dépannage
Timeout de streaming — Utilisez toujours client.messages.stream() lorsque la réflexion étendue est activée. Les appels non-streaming avec de grandes valeurs budget_tokens expireront au niveau de la couche HTTP avant que le modèle ne termine.
model_not_available — L'accès à Fable 5 a été rétabli le 1er juillet 2026 après la suspension liée aux contrôles d'exportation de juin. Si l'erreur persiste, vérifiez votre niveau de compte sur console.anthropic.com — Fable 5 nécessite une clé API avec facturation à l'usage activée.
Context length exceeded — Avec 1 million de tokens, c'est rare, mais les très grands monorepos avec de nombreux fichiers lock et du code généré peuvent l'atteindre. Ajoutez .lock, .snap et .d.ts à la liste des extensions bloquées dans tools.ts.
Coût élevé à la première exécution — Le premier tour ne bénéficie pas du cache (rien n'est encore mis en cache). Les coûts diminuent de 90% à partir du deuxième tour.
Prochaines étapes
- Ajouter un outil d'écriture de fichier — permettre à l'agent de sauvegarder le rapport sous
code-review.mdà la racine du projet - Intégration GitHub Actions — exécuter l'agent automatiquement sur chaque pull request et poster les résultats comme commentaires
- Sous-agents spécialisés — utiliser l'API Beta Managed Agents pour lancer en parallèle des analyseurs de sécurité, performance et style qui rapportent à un orchestrateur Fable 5
Conclusion
Claude Fable 5 change ce qu'un seul agent TypeScript peut accomplir en une session ininterrompue. La fenêtre de contexte d'un million de tokens élimine la jonglerie de contexte qui rend les agents longue durée fragiles. La réflexion étendue apporte un raisonnement soigneux et multi-étapes à l'analyse de sécurité. Et le cache de prompts transforme ce qui pourrait être un processus coûteux en quelque chose d'économiquement viable pour chaque pull request.
Les patterns ici — streaming en premier, limite d'itérations, mise en cache des blocs statiques — sont le bon fondement pour tout workflow alimenté par Fable 5. Avec la facturation à l'usage désormais active, le modèle est accessible sans prérequis d'abonnement. Commencez petit, mesurez l'utilisation des tokens sur du vrai code, puis passez aux tâches qui auraient précédemment nécessité un relecteur humain devant un terminal pendant des heures.