Documents the migration from @anthropic-ai/sdk to @anthropic-ai/claude-agent-sdk with phases, code examples, and progress tracking. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
17 KiB
Plan de Migration : API Anthropic → Claude Agent SDK TypeScript
Version 1.1 - Janvier 2026 Migration du backend Ikario vers le Claude Agent SDK
Statut de Migration (mise à jour: 31 janvier 2026)
| Phase | Statut | Notes |
|---|---|---|
| Phase 0 | ✅ TERMINÉ | Token OAuth configuré, SDK installé, backups créés |
| Phase 1 | ✅ TERMINÉ | agentSdkService.js créé avec toutes les fonctions |
| Phase 2 | ✅ TERMINÉ | messages.js et claude.js migrés vers SDK |
| Phase 3 | ✅ TERMINÉ | @anthropic-ai/sdk supprimé de package.json |
| Phase 4 | ⏳ À FAIRE | Tests et validation |
| Phase 5 | ⏳ À FAIRE | Mode AGENT auto-poïétique |
Fichiers backupés (backups/pre-agent-sdk/):
messages.js,claude.js,unifiedRagClient.js,tavilyMcpClient.js,toolExecutor.js
Note: Les clients MCP (unifiedRagClient.js, etc.) sont conservés car utilisés par les routes directes (/api/rag, /api/memory, /api/tavily) pour l'accès hors-contexte chat.
Contexte
Objectif
Remplacer l'utilisation de l'API Anthropic (@anthropic-ai/sdk avec ANTHROPIC_API_KEY) par le Claude Agent SDK (@anthropic-ai/claude-agent-sdk avec CLAUDE_CODE_OAUTH_TOKEN).
Pourquoi ?
- Unification : Un seul SDK pour le chat ET les capacités agent
- Simplification : Le SDK gère automatiquement la boucle tool-use
- MCP intégré : Les serveurs MCP sont déclarés dans les options, plus besoin de clients séparés
- Auto-poïétique : Permet à Ikario de se modifier lui-même (Phase 5)
Décision architecturale
- SDK choisi : TypeScript (
@anthropic-ai/claude-agent-sdk) - intégration directe dans le backend Node.js - Extended Thinking : Le contenu "thinking" ne sera plus affiché au frontend (limitation du SDK)
Architecture
Avant (actuel)
Frontend (React)
↓
Backend (Express)
↓
@anthropic-ai/sdk (ANTHROPIC_API_KEY)
↓
anthropic.messages.stream()
↓
Boucle while pour tool_use
↓
toolExecutor.js
↓
4 MCP Clients séparés:
├── unifiedRagClient.js (Weaviate)
├── tavilyMcpClient.js (Internet)
├── libraryRagMcpClient.js (Documents)
└── mcpClient.js (base)
Après (cible)
Frontend (React)
↓
Backend (Express)
↓
@anthropic-ai/claude-agent-sdk (CLAUDE_CODE_OAUTH_TOKEN)
↓
query() avec for await (streaming)
↓
Gestion automatique des tools par le SDK
↓
MCP servers dans options.mcpServers:
├── unified_rag (stdio → Python)
└── tavily (stdio → npx)
SDK TypeScript - Référence
Installation
npm install @anthropic-ai/claude-agent-sdk
API principale
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Your prompt",
options: {
model: "claude-opus-4-5-20251101",
systemPrompt: "Tu es Ikario...",
maxThinkingTokens: 5000,
mcpServers: {
unified_rag: {
command: "python",
args: ["/path/to/mcp_server.py"],
env: { WEAVIATE_URL: "http://localhost:8080" }
}
},
allowedTools: ["mcp__unified_rag__*"],
permissionMode: "bypassPermissions"
}
})) {
if (message.type === 'result' && message.subtype === 'success') {
console.log(message.result);
}
}
Types de messages
| Type | Description |
|---|---|
system (subtype: init) |
Initialisation, liste des MCP servers |
assistant |
Réponse avec content blocks (text, tool_use) |
result |
Résultat final avec usage, cost, duration |
Options disponibles
| Option | Type | Description |
|---|---|---|
model |
string | Modèle Claude à utiliser |
systemPrompt |
string | Prompt système |
maxThinkingTokens |
number | Budget Extended Thinking (1024-32000) |
mcpServers |
object | Configuration des serveurs MCP |
allowedTools |
string[] | Outils autorisés (wildcards supportés) |
permissionMode |
string | default, acceptEdits, bypassPermissions |
cwd |
string | Répertoire de travail |
hooks |
object | Hooks PreToolUse, PostToolUse, etc. |
Phases de Migration
Phase 0 : Préparation (1 jour)
| Tâche | Description | Commande/Action |
|---|---|---|
| 0.1 | Générer le token OAuth | claude setup-token |
| 0.2 | Ajouter au .env d'Ikario |
CLAUDE_CODE_OAUTH_TOKEN='...' |
| 0.3 | Installer le SDK | cd server && npm install @anthropic-ai/claude-agent-sdk |
| 0.4 | Créer branche Git | git checkout -b feature/agent-sdk-migration |
| 0.5 | Backup fichiers actuels | Copier messages.js, claude.js, etc. |
Validation Phase 0 :
# Vérifier le token
echo $CLAUDE_CODE_OAUTH_TOKEN
# Vérifier le package
cd generations/ikario/server && npm ls @anthropic-ai/claude-agent-sdk
Phase 1 : Service Agent SDK (2-3 jours)
Objectif : Créer server/services/agentSdkService.js
1.1 Structure du service
// server/services/agentSdkService.js
import { query } from "@anthropic-ai/claude-agent-sdk";
/**
* Crée une query Agent SDK avec la configuration Ikario
*/
export function createAgentQuery(prompt, ikarioOptions = {}) {
const {
model = "claude-sonnet-4-5-20250929",
systemPrompt = "",
thinkingBudget = 5000,
enableMemory = true,
enableTavily = false,
cwd = null,
additionalTools = []
} = ikarioOptions;
// Construire les MCP servers
const mcpServers = {};
const allowedTools = [];
if (enableMemory) {
mcpServers.unified_rag = {
command: "python",
args: [process.env.UNIFIED_RAG_SERVER_PATH],
env: {
WEAVIATE_URL: process.env.WEAVIATE_URL,
WEAVIATE_API_KEY: process.env.WEAVIATE_API_KEY || ""
}
};
allowedTools.push("mcp__unified_rag__*");
}
if (enableTavily && process.env.TAVILY_API_KEY) {
mcpServers.tavily = {
command: "npx",
args: ["-y", "@anthropic-ai/mcp-tavily"],
env: {
TAVILY_API_KEY: process.env.TAVILY_API_KEY
}
};
allowedTools.push("mcp__tavily__*");
}
// Ajouter les outils supplémentaires
allowedTools.push(...additionalTools);
return query({
prompt,
options: {
model,
systemPrompt,
maxThinkingTokens: thinkingBudget,
mcpServers,
allowedTools,
permissionMode: "bypassPermissions",
...(cwd && { cwd })
}
});
}
/**
* Construit le system prompt complet pour Ikario
*/
export function buildIkarioSystemPrompt(options = {}) {
const {
globalInstructions = "",
projectInstructions = "",
enableMemory = true,
enableTavily = false
} = options;
const parts = [];
// Date/Heure
const now = new Date();
parts.push(`## Date et Heure Actuelles
Date: ${now.toLocaleDateString('fr-FR', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}
Heure: ${now.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })}
Fuseau: ${Intl.DateTimeFormat().resolvedOptions().timeZone}`);
// Instructions globales
if (globalInstructions.trim()) {
parts.push(`## Instructions Globales\n${globalInstructions.trim()}`);
}
// Instructions projet
if (projectInstructions.trim()) {
parts.push(`## Instructions Projet\n${projectInstructions.trim()}`);
}
// Mémoire
if (enableMemory) {
parts.push(`## Mémoire
Tu as une mémoire persistante. Les conversations sont sauvegardées AUTOMATIQUEMENT.
Utilise add_thought pour tes réflexions internes, search_memories pour chercher.`);
}
// Internet
if (enableTavily) {
parts.push(`## Internet
Tu as accès à internet via Tavily: tavily_search (web), tavily_search_news (actualités).
Cite tes sources.`);
}
return parts.join('\n\n');
}
1.2 Tests du service
// server/services/__tests__/agentSdkService.test.js
import { createAgentQuery, buildIkarioSystemPrompt } from '../agentSdkService.js';
// Test basique
async function testBasicQuery() {
const q = createAgentQuery("Dis bonjour", {
model: "claude-sonnet-4-5-20250929",
systemPrompt: "Tu es Ikario.",
enableMemory: false,
enableTavily: false
});
for await (const message of q) {
console.log(message.type, message);
if (message.type === 'result') {
console.log("Résultat:", message.result);
}
}
}
Validation Phase 1 :
# Test manuel du service
node -e "
import('./services/agentSdkService.js').then(async ({ createAgentQuery }) => {
const q = createAgentQuery('Dis bonjour', { enableMemory: false });
for await (const m of q) {
if (m.type === 'result') console.log(m.result);
}
});
"
Phase 2 : Migration Route Messages (2-3 jours)
Objectif : Modifier server/routes/messages.js pour utiliser le SDK
2.1 Changements principaux
| Avant | Après |
|---|---|
import Anthropic from '@anthropic-ai/sdk' |
import { createAgentQuery, buildIkarioSystemPrompt } from '../services/agentSdkService.js' |
const anthropic = new Anthropic({ apiKey }) |
Supprimé (le SDK utilise CLAUDE_CODE_OAUTH_TOKEN) |
anthropic.messages.stream({...}) |
createAgentQuery(prompt, options) |
stream.on('text', ...) |
for await (const message of query) |
| Boucle while tool_use | Supprimée (automatique) |
2.2 Mapping SSE
// Nouveau code streaming
const q = createAgentQuery(content, {
model: conversation.model,
systemPrompt: buildIkarioSystemPrompt({
globalInstructions,
projectInstructions,
enableMemory: true,
enableTavily: conversation.enable_internet
}),
thinkingBudget: conversation.thinking_budget_tokens,
enableMemory: true,
enableTavily: conversation.enable_internet
});
for await (const message of q) {
// Messages assistant avec contenu
if (message.type === 'assistant') {
for (const block of message.message.content) {
if (block.type === 'text') {
res.write(`data: ${JSON.stringify({ type: 'content', text: block.text })}\n\n`);
}
if (block.type === 'tool_use') {
res.write(`data: ${JSON.stringify({ type: 'tool_use', name: block.name })}\n\n`);
}
}
}
// Résultat final
if (message.type === 'result') {
if (message.subtype === 'success') {
res.write(`data: ${JSON.stringify({
type: 'done',
id: assistantMessageId,
usage: {
inputTokens: message.usage?.input_tokens || 0,
outputTokens: message.usage?.output_tokens || 0
}
})}\n\n`);
} else {
res.write(`data: ${JSON.stringify({
type: 'error',
message: message.result || 'Erreur inconnue'
})}\n\n`);
}
}
}
2.3 Fichiers à modifier
| Fichier | Modifications |
|---|---|
server/routes/messages.js |
Route principale streaming |
server/routes/claude.js |
Route API Claude (si utilisée) |
server/index.js |
Supprimer init des anciens clients MCP |
Validation Phase 2 :
# Test streaming
curl -X POST http://localhost:3001/api/conversations/test-conv-id/messages/stream \
-H "Content-Type: application/json" \
-d '{"content": "Bonjour Ikario"}'
Phase 3 : Nettoyage (1-2 jours)
Objectif : Supprimer le code obsolète
3.1 Fichiers à supprimer
# Services MCP obsolètes
rm server/services/unifiedRagClient.js
rm server/services/tavilyMcpClient.js
rm server/services/libraryRagMcpClient.js
rm server/services/mcpClient.js
rm server/services/toolExecutor.js
# Configs tools obsolètes (optionnel - peuvent être gardées comme référence)
# rm server/config/memoryTools.js
# rm server/config/tavilyTools.js
# rm server/config/libraryRagTools.js
3.2 Dépendances à supprimer
cd server
npm uninstall @anthropic-ai/sdk
3.3 Nettoyage des imports
Rechercher et supprimer dans tous les fichiers :
import Anthropic from '@anthropic-ai/sdk'import { ... } from '../services/unifiedRagClient.js'import { ... } from '../services/tavilyMcpClient.js'import { ... } from '../services/toolExecutor.js'
Validation Phase 3 :
# Vérifier qu'il n'y a plus de références aux anciens fichiers
grep -r "unifiedRagClient" server/
grep -r "tavilyMcpClient" server/
grep -r "toolExecutor" server/
grep -r "@anthropic-ai/sdk" server/
Phase 4 : Tests et Validation (2 jours)
| Test | Description | Commande |
|---|---|---|
| 4.1 | Streaming SSE | Envoyer message, vérifier réponse temps réel |
| 4.2 | Outils mémoire | add_thought, search_thoughts, search_memories |
| 4.3 | Tavily | Recherche internet (si activé) |
| 4.4 | Images | Upload et analyse d'images |
| 4.5 | Tokens | Vérifier compteur tokens correct |
| 4.6 | Conversations | Multi-tours, contexte préservé |
| 4.7 | Projets | Instructions projet appliquées |
Script de test complet :
# Test conversation complète
./tests/test_agent_sdk_integration.sh
Phase 5 : Mode AGENT Auto-poïétique (3-4 jours)
Objectif : Permettre à Ikario de modifier son propre code
5.1 Nouvelle route
// server/routes/agent.js
import express from 'express';
import { query } from '@anthropic-ai/claude-agent-sdk';
const router = express.Router();
// POST /api/agent/evolve
router.post('/evolve', async (req, res) => {
const { task, context } = req.body;
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
const q = query({
prompt: `
Contexte: ${context}
Tâche: ${task}
Instructions:
1. Analyse le code actuel avec Read/Grep
2. Planifie les modifications
3. Implémente avec Edit/Write
4. Documente dans la mémoire (add_thought)
`,
options: {
model: "claude-opus-4-5-20251101",
systemPrompt: "Tu es Ikario en mode auto-modification...",
allowedTools: [
"Read", "Write", "Edit", "Glob", "Grep", "Bash",
"mcp__unified_rag__add_thought",
"mcp__unified_rag__search_thoughts"
],
mcpServers: {
unified_rag: {
command: "python",
args: [process.env.UNIFIED_RAG_SERVER_PATH],
env: { WEAVIATE_URL: process.env.WEAVIATE_URL }
}
},
cwd: process.env.IKARIO_PROJECT_DIR,
hooks: {
PreToolUse: [{
matcher: 'Write|Edit',
hooks: [protectSensitiveFiles]
}]
},
permissionMode: "acceptEdits"
}
});
for await (const message of q) {
res.write(`data: ${JSON.stringify(message)}\n\n`);
}
res.end();
});
// Hook de sécurité
async function protectSensitiveFiles(input, toolUseID, { signal }) {
const filePath = input.tool_input?.file_path || '';
const fileName = filePath.split('/').pop();
const protected = ['.env', 'api-key', 'credentials', 'secret'];
if (protected.some(p => fileName.includes(p))) {
return {
hookSpecificOutput: {
hookEventName: input.hook_event_name,
decision: 'deny',
reason: `Fichier protégé: ${fileName}`
}
};
}
return {};
}
export default router;
5.2 Variables d'environnement
Ajouter dans .env :
IKARIO_PROJECT_DIR=/path/to/generations/ikario
5.3 UI (optionnel)
Créer un composant React pour déclencher l'auto-modification depuis l'interface.
Variables d'Environnement Finales
# === CLAUDE AGENT SDK (nouveau) ===
CLAUDE_CODE_OAUTH_TOKEN='your-oauth-token' # De: claude setup-token
# === WEAVIATE (inchangé) ===
WEAVIATE_URL=http://localhost:8080
WEAVIATE_API_KEY= # Optionnel pour cloud
# === UNIFIED RAG MCP (inchangé) ===
UNIFIED_RAG_SERVER_PATH=/path/to/library_rag/mcp_server.py
# === TAVILY (inchangé) ===
TAVILY_API_KEY=tvly-xxxxx
# === MODE AGENT (nouveau) ===
IKARIO_PROJECT_DIR=/path/to/generations/ikario
# === OBSOLÈTES (à supprimer) ===
# ANTHROPIC_API_KEY=sk-ant-xxxxx # Plus nécessaire
Récapitulatif
| Phase | Durée | Objectif | Livrable |
|---|---|---|---|
| 0 | 1 jour | Préparation | Token, package, branche |
| 1 | 2-3 jours | Service SDK | agentSdkService.js |
| 2 | 2-3 jours | Migration routes | messages.js modifié |
| 3 | 1-2 jours | Nettoyage | Anciens fichiers supprimés |
| 4 | 2 jours | Tests | Validation complète |
| 5 | 3-4 jours | Mode AGENT | /api/agent/evolve |
Total : 11-15 jours
Breaking Changes
- Extended Thinking : Le contenu "thinking" n'est plus affiché au frontend
- API Key :
ANTHROPIC_API_KEYremplacé parCLAUDE_CODE_OAUTH_TOKEN - MCP Clients : Les 4 clients séparés sont supprimés
- toolExecutor : Supprimé, géré automatiquement par le SDK
Rollback
En cas de problème, restaurer depuis la branche main :
git checkout main
git branch -D feature/agent-sdk-migration
Document créé le 31 janvier 2026 Migration vers Claude Agent SDK TypeScript