Construire un agent IA type Claude Code avec Claude Agent SDK (TypeScript)
Updated on
Si vous avez déjà utilisé Claude Code ou d’autres copilotes IA pour le code, vous savez à quel point cela peut sembler magique : vous tapez des questions dans un panneau, et une IA qui « se souvient » de la session vous aide à raisonner sur le code, exécuter des outils et vous débloquer.
Avec le Claude Agent SDK, vous pouvez construire votre propre agent à la Claude Code en Node.js avec étonnamment peu de code.
Dans ce guide, nous allons voir :
- La mise en place d’un projet TypeScript
- L’envoi de votre première requête avec
query() - La création d’une session de conversation persistante
- La construction d’une expérience de chat en ligne de commande
- L’ajout d’un outil de calcul via MCP pour que l’agent puisse « utiliser une calculatrice »
Tous les exemples utilisent TypeScript + Node.js et sont volontairement structurés et nommés de façon à être faciles à adapter à votre propre projet.
1. Mise en place du projet
Créez un nouveau projet :
mkdir dev-assistant-agent
cd dev-assistant-agent
npm init -yInstallez les dépendances :
npm install @anthropic-ai/claude-agent-sdk
npm install typescript tsx @types/node
npx tsc --initNous allons aussi utiliser dotenv pour charger les variables d’environnement :
npm install dotenvCréez un fichier .env à la racine du projet :
ANTHROPIC_API_KEY=your_api_key_here
ANTHROPIC_BASE_URL=https://api.anthropic.comEt un petit module de configuration :
// src/config/runtime.ts
import 'dotenv/config';
export const API_KEY = process.env.ANTHROPIC_API_KEY;
export const BASE_URL = process.env.ANTHROPIC_BASE_URL;
if (!API_KEY) {
throw new Error('ANTHROPIC_API_KEY is not set.');
}2. Premier contact : appel minimal d’agent
Le cœur du Claude Agent SDK est la fonction query(). Au lieu de renvoyer une grande chaîne de caractères, elle renvoie un itérateur asynchrone de messages (messages système, messages assistant, etc.). Vous pouvez les diffuser et les traiter au fil de leur arrivée.
Créez un simple exemple « hello » :
// src/agent/helloAgent.ts
import { query, type Query } from '@anthropic-ai/claude-agent-sdk';
export async function runHelloAgent() {
const stream: Query = query({
prompt: 'Hi Claude, what can you do?',
});
for await (const item of stream) {
if (item.type === 'assistant') {
for (const chunk of item.message.content) {
if (chunk.type === 'text') {
console.log(chunk.text);
}
}
}
}
}Point d’entrée :
// src/main.ts
import { runHelloAgent } from './agent/helloAgent';
async function main() {
console.log('Launching hello agent...');
await runHelloAgent();
}
main().catch(console.error);Lancez :
npx tsx src/main.tsVous devriez voir Claude décrire ce qu’il peut faire — cela confirme que le SDK est correctement connecté.
3. Sessions de conversation : permettre à l’agent de se souvenir
Une réponse ponctuelle, c’est bien ; un assistant qui se souvient de la conversation, c’est mieux.
Le Claude Agent SDK prend en charge les sessions. Chaque conversation possède un session_id. Lorsque vous démarrez un nouveau query(), vous pouvez passer une option resume pour reprendre une session existante.
Voici une petite abstraction qui envoie un prompt et renvoie l’éventuel session_id fourni par le SDK :
// src/agent/sessionClient.ts
import { query, type Query } from '@anthropic-ai/claude-agent-sdk';
export async function sendMessageWithSession(
userText: string,
previousSessionId?: string
): Promise<{ sessionId?: string }> {
let activeSessionId = previousSessionId;
const stream: Query = query({
prompt: userText,
options: {
resume: previousSessionId,
},
});
for await (const item of stream) {
switch (item.type) {
case 'system':
if (item.subtype === 'init') {
activeSessionId = item.session_id;
console.log(`(session started: ${activeSessionId})`);
}
break;
case 'assistant':
for (const piece of item.message.content) {
if (piece.type === 'text') {
console.log(`Claude: ${piece.text}`);
}
}
break;
}
}
return { sessionId: activeSessionId };
}Vous pouvez le tester comme ceci :
// src/examples/sessionDemo.ts
import { sendMessageWithSession } from '../agent/sessionClient';
export async function runSessionDemo() {
let sessionId: string | undefined;
// Première question
const first = await sendMessageWithSession('Hello, who are you?', sessionId);
sessionId = first.sessionId;
// Deuxième question, même conversation
const second = await sendMessageWithSession(
'What did I just ask you?',
sessionId
);
sessionId = second.sessionId;
}Claude peut maintenant répondre à des questions sur les tours précédents, parce que vous réutilisez la même session.
4. Construire une expérience de chat en CLI
Transformons cela en une petite application de chat en ligne de commande.
Nous allons :
- Utiliser le module
readlinede Node - Conserver un
sessionIdentre les tours - Envoyer chaque message utilisateur via
sendMessageWithSession
Créez un fichier uniquement pour la boucle CLI :
// src/cli/chatLoop.ts
import readline from 'readline';
import { sendMessageWithSession } from '../agent/sessionClient';
export async function startCliConversation() {
let sessionId: string | undefined;
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: 'You: ',
});
console.log('Interactive Claude Agent CLI');
console.log('Type your message and press Enter. Ctrl+C to quit.\n');
rl.prompt();
rl.on('line', async (line) => {
const trimmed = line.trim();
if (!trimmed) {
rl.prompt();
return;
}
try {
const { sessionId: newSessionId } = await sendMessageWithSession(
trimmed,
sessionId
);
sessionId = newSessionId;
} catch (err) {
console.error('Error talking to agent:', err);
}
rl.prompt();
});
rl.on('close', () => {
console.log('\nGoodbye!');
process.exit(0);
});
}Modifiez le point d’entrée pour utiliser la CLI :
// src/main.ts
import { startCliConversation } from './cli/chatLoop';
startCliConversation().catch(console.error);Lancez :
npx tsx src/main.tsVous avez maintenant un « Claude Code sans interface graphique » : un terminal qui maintient le contexte entre les tours et répond en temps réel.
5. Donner des outils à l’agent via MCP (exemple : outil de calcul)
L’une des parties les plus intéressantes de Claude Code est l’usage d’outils — le modèle peut décider quand :
- Appeler une calculatrice
- Rechercher dans des fichiers
- Exécuter des commandes
- Interroger des APIs
Avec le Claude Agent SDK, vous pouvez ajouter des outils via le Model Context Protocol (MCP). Implémentons un outil de calcul pour que l’agent puisse évaluer précisément des expressions au lieu de faire du calcul mental approximatif.
5.1 Installer des dépendances supplémentaires
Nous allons utiliser mathjs (opens in a new tab) et zod pour la validation de schéma :
npm install mathjs zod@3.25.76(L’utilisation de Zod 3.x évite des problèmes de compatibilité avec les versions plus récentes.)
5.2 Un petit utilitaire de calcul
// src/tools/mathEvaluator.ts
import * as math from 'mathjs';
export function evaluateMathExpression(expression: string): string {
const result = math.evaluate(expression);
return result.toString();
}5.3 Définir un outil pour l’agent
Le SDK expose un helper tool. Nous allons définir un outil appelé numeric_calculator qui prend une chaîne expression.
// src/tools/mathTool.ts
import { tool } from '@anthropic-ai/claude-agent-sdk';
import { z } from 'zod';
import { evaluateMathExpression } from './mathEvaluator';
export const numericCalculatorTool = tool(
'numeric_calculator',
'Evaluate a mathematical expression using mathjs, e.g. "(2 + 3) * 4".',
{
expression: z.string().describe('A valid math expression.'),
},
async (args) => {
const output = evaluateMathExpression(args.expression);
return {
content: [
{
type: 'text',
text: output,
},
],
};
}
);5.4 Exposer les outils via un serveur MCP
Nous regroupons maintenant un ou plusieurs outils dans un serveur MCP :
// src/mcp/toolkitServer.ts
import { createSdkMcpServer } from '@anthropic-ai/claude-agent-sdk';
import { numericCalculatorTool } from '../tools/mathTool';
export const toolsetServer = createSdkMcpServer({
name: 'toolset',
version: '1.0.0',
tools: [numericCalculatorTool],
});5.5 Mettre à jour la CLI pour prendre en charge les outils
Nous allons créer une version de la fonction d’envoi de message qui connaît les outils, puis l’intégrer dans notre boucle CLI.
// src/agent/toolEnabledClient.ts
import { query, type Query } from '@anthropic-ai/claude-agent-sdk';
import { toolsetServer } from '../mcp/toolkitServer';
export async function sendMessageWithTools(
userText: string,
previousSessionId?: string
): Promise<{ sessionId?: string }> {
let activeSessionId = previousSessionId;
const stream: Query = query({
prompt: userText,
options: {
resume: previousSessionId,
systemPrompt:
'You are a helpful assistant. When you need to do precise math, use the numeric_calculator tool instead of guessing.',
mcpServers: {
toolset: toolsetServer,
},
// Les noms d’outils suivent le format : mcp__{server_name}__{tool_name}
allowedTools: ['mcp__toolset__numeric_calculator'],
},
});
for await (const item of stream) {
switch (item.type) {
case 'system':
if (item.subtype === 'init') {
activeSessionId = item.session_id;
console.log(`(session: ${activeSessionId})`);
}
break;
case 'assistant':
for (const piece of item.message.content) {
if (piece.type === 'text') {
console.log(`Claude: ${piece.text}`);
} else if (piece.type === 'tool_use') {
console.log(
`[tool call] ${piece.name} with input: ${JSON.stringify(
piece.input
)}`
);
}
}
break;
case 'user':
// Les résultats d’outils reviennent sous forme de message utilisateur spécial
for (const piece of item.message.content) {
if (piece.type === 'tool_result') {
process.stdout.write('[tool result] ');
for (const inner of piece.content) {
if (inner.type === 'text') {
process.stdout.write(inner.text);
}
}
process.stdout.write('\n');
}
}
break;
}
}
return { sessionId: activeSessionId };
}Créez maintenant une boucle CLI séparée qui utilise ce client compatible outils :
// src/cli/chatWithTools.ts
import readline from 'readline';
import { sendMessageWithTools } from '../agent/toolEnabledClient';
export async function startCliWithTools() {
let sessionId: string | undefined;
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: 'You: ',
});
console.log('Claude Agent CLI (with math tool)');
console.log('Ask me something like: (2454 + 23546)^2 / 32');
rl.prompt();
rl.on('line', async (line) => {
const text = line.trim();
if (!text) {
rl.prompt();
return;
}
try {
const { sessionId: nextSessionId } = await sendMessageWithTools(
text,
sessionId
);
sessionId = nextSessionId;
} catch (err) {
console.error('Error:', err);
}
rl.prompt();
});
rl.on('close', () => {
console.log('\nSession ended.');
process.exit(0);
});
}Mettez à jour src/main.ts pour lancer cette version avec outils :
// src/main.ts
import { startCliWithTools } from './cli/chatWithTools';
startCliWithTools().catch(console.error);À présent, lorsque vous demandez :
You: (2454 + 23546)^2 / 32Vous devriez voir :
- Un log indiquant que l’outil a été appelé
- Le résultat numérique affiché comme résultat d’outil
- Une explication en langage naturel de Claude résumant la réponse
Félicitations — vous avez maintenant un agent type Claude qui peut discuter, se souvenir et appeler des outils.
6. Idées pour étendre votre agent
Une fois ce squelette opérationnel, vous pouvez commencer à ajouter d’autres fonctionnalités à la Claude Code :
-
Outils orientés codebase
Des outils qui lisent des fichiers de votre dépôt, recherchent du texte ou résument de gros fichiers. -
Outils d’exécution
Des outils qui lancent des tests, scripts ou petits extraits de code dans un environnement contrôlé. -
Prompts système adaptés au projet
Injecter des métadonnées de projet, des documents d’architecture ou des guides de style dans lesystemPromptpour que l’agent paraisse « natif au projet ». -
Sessions persistantes par utilisateur
Stocker lesession_iddans une base de données associée à vos comptes utilisateurs, afin que chacun dispose d’un assistant à long terme.
Le Claude Agent SDK vous fournit les briques de base. À quel point votre agent se rapprochera de Claude Code dépend entièrement des outils, des prompts et de l’interface que vous construirez autour.