diff --git a/prompts/extended_thinking_spec.md b/prompts/extended_thinking_spec.md
new file mode 100644
index 0000000..1e7acbd
--- /dev/null
+++ b/prompts/extended_thinking_spec.md
@@ -0,0 +1,1360 @@
+# Extended Thinking Feature Specification
+## Claude.ai Clone - Enhanced Reasoning Integration
+
+---
+
+## 1. Vue d'ensemble
+
+Extended Thinking est une fonctionnalité de Claude qui permet d'activer des capacités de raisonnement améliorées pour les tâches complexes. Claude génère des blocs `thinking` où il expose son processus de réflexion interne étape par étape avant de fournir sa réponse finale.
+
+### Fonctionnement
+- Claude crée des blocs `thinking` contenant son raisonnement interne
+- Ces blocs sont suivis de blocs `text` avec la réponse finale
+- Le processus de réflexion est résumé (pour Claude 4+) mais facturé au tarif complet
+- Améliore significativement la qualité des réponses pour les tâches complexes
+
+### Cas d'usage
+- Mathématiques complexes et calculs
+- Programmation et débogage
+- Analyse approfondie de documents
+- Raisonnement logique multi-étapes
+- Résolution de problèmes complexes
+
+---
+
+## 2. Modèles supportés
+
+| Modèle | ID | Support Extended Thinking |
+|--------|----|-----------------------------|
+| Claude Sonnet 4.5 | claude-sonnet-4-5-20250929 | ✅ Oui |
+| Claude Sonnet 4 | claude-sonnet-4-20250514 | ✅ Oui |
+| Claude Haiku 4.5 | claude-haiku-4-5-20251001 | ✅ Oui |
+| Claude Opus 4.5 | claude-opus-4-5-20251101 | ✅ Oui (avec préservation thinking) |
+| Claude Opus 4.1 | claude-opus-4-1-20250805 | ✅ Oui |
+| Claude Opus 4 | claude-opus-4-20250514 | ✅ Oui |
+| Claude Sonnet 3.7 | claude-3-7-sonnet-20250219 | ✅ Oui (déprécié, thinking complet) |
+
+**Note**: Claude 4+ retourne du thinking résumé. Claude 3.7 retourne du thinking complet.
+
+---
+
+## 3. Architecture Backend
+
+### 3.1 Modifications API Routes
+
+#### `server/routes/claude.js`
+
+**Ajouts nécessaires**:
+
+```javascript
+// POST /api/claude/chat - Non-streaming avec thinking
+router.post('/chat', async (req, res) => {
+ const {
+ messages,
+ model,
+ system,
+ maxTokens = 4096,
+ temperature = 1,
+ enableMemoryTools = true,
+ // Nouveaux paramètres thinking
+ enableThinking = false,
+ thinkingBudgetTokens = 10000
+ } = req.body;
+
+ const apiParams = {
+ model,
+ max_tokens: maxTokens,
+ temperature,
+ system: buildSystemPrompt(system, enableMemoryTools),
+ messages: conversationMessages
+ };
+
+ // Ajouter thinking si activé
+ if (enableThinking) {
+ apiParams.thinking = {
+ type: 'enabled',
+ budget_tokens: thinkingBudgetTokens
+ };
+ }
+
+ // Ajouter tools si activé
+ if (tools.length > 0) {
+ apiParams.tools = tools;
+ }
+
+ const response = await anthropic.messages.create(apiParams);
+ // ... rest of logic
+});
+```
+
+#### `server/routes/messages.js`
+
+**Modifications dans les endpoints de streaming**:
+
+```javascript
+// POST /:conversationId/messages/stream
+router.post('/:conversationId/messages', async (req, res) => {
+ // Parse settings avec thinking support
+ const settings = JSON.parse(conversation.settings || '{}');
+ const model = conversation.model || 'claude-sonnet-4-5-20250929';
+ const temperature = settings.temperature || 1;
+ const maxTokens = settings.maxTokens || 4096;
+ const enableThinking = settings.enableThinking || false;
+ const thinkingBudgetTokens = settings.thinkingBudgetTokens || 10000;
+
+ // Build request options
+ const requestOptions = {
+ model,
+ max_tokens: maxTokens,
+ temperature,
+ messages: conversationMessages
+ };
+
+ // Add thinking if enabled
+ if (enableThinking) {
+ requestOptions.thinking = {
+ type: 'enabled',
+ budget_tokens: thinkingBudgetTokens
+ };
+ }
+
+ // Add system prompt
+ if (systemPrompt) {
+ requestOptions.system = systemPrompt;
+ }
+
+ // Add tools
+ if (tools.length > 0) {
+ requestOptions.tools = tools;
+ }
+
+ // Create streaming response
+ const stream = await anthropic.messages.stream(requestOptions);
+
+ // Handle thinking deltas in stream
+ for await (const event of stream) {
+ if (event.type === 'content_block_start') {
+ if (event.content_block.type === 'thinking') {
+ console.log('[Messages] Thinking block started');
+ res.write(`data: ${JSON.stringify({
+ type: 'thinking_start',
+ index: event.index
+ })}\n\n`);
+ }
+ } else if (event.type === 'content_block_delta') {
+ if (event.delta.type === 'thinking_delta') {
+ fullThinkingContent += event.delta.thinking;
+ res.write(`data: ${JSON.stringify({
+ type: 'thinking',
+ text: event.delta.thinking
+ })}\n\n`);
+ } else if (event.delta.type === 'text_delta') {
+ fullContent += event.delta.text;
+ res.write(`data: ${JSON.stringify({
+ type: 'content',
+ text: event.delta.text
+ })}\n\n`);
+ }
+ }
+ }
+});
+```
+
+### 3.2 Nouveaux Types de Réponse
+
+**Structure de réponse avec thinking**:
+
+```javascript
+{
+ "content": [
+ {
+ "type": "thinking",
+ "thinking": "Let me analyze this step by step...",
+ "signature": "WaUjzkypQ2mUEVM36O2TxuC06KN8xyfbJwyem2dw3URve..."
+ },
+ {
+ "type": "text",
+ "text": "Based on my analysis..."
+ }
+ ]
+}
+```
+
+**Events de streaming**:
+
+```javascript
+// Événement de début de thinking
+{
+ "type": "thinking_start",
+ "index": 0
+}
+
+// Événement de delta thinking
+{
+ "type": "thinking",
+ "text": "Let me analyze..."
+}
+
+// Événement de fin de thinking (automatique avec content_block_stop)
+{
+ "type": "thinking_stop",
+ "index": 0
+}
+
+// Événements de contenu normal
+{
+ "type": "content",
+ "text": "Based on..."
+}
+```
+
+### 3.3 Base de Données
+
+#### Modifications du schéma `conversations`
+
+```sql
+-- Ajouter colonne pour activer thinking par conversation
+ALTER TABLE conversations ADD COLUMN enable_thinking INTEGER DEFAULT 0;
+ALTER TABLE conversations ADD COLUMN thinking_budget_tokens INTEGER DEFAULT 10000;
+```
+
+#### Modifications du schéma `messages`
+
+```sql
+-- Ajouter colonne pour stocker thinking content
+ALTER TABLE messages ADD COLUMN thinking_content TEXT DEFAULT NULL;
+ALTER TABLE messages ADD COLUMN thinking_signature TEXT DEFAULT NULL;
+```
+
+**Migration dans `server/db/index.js`**:
+
+```javascript
+// Add thinking columns if they don't exist
+const hasThinkingColumns = db.prepare(`
+ SELECT COUNT(*) as count FROM pragma_table_info('conversations')
+ WHERE name IN ('enable_thinking', 'thinking_budget_tokens')
+`).get();
+
+if (hasThinkingColumns.count < 2) {
+ console.log('Adding thinking columns to conversations table...');
+ db.exec(`
+ ALTER TABLE conversations ADD COLUMN enable_thinking INTEGER DEFAULT 0;
+ ALTER TABLE conversations ADD COLUMN thinking_budget_tokens INTEGER DEFAULT 10000;
+ `);
+}
+
+const hasMessageThinking = db.prepare(`
+ SELECT COUNT(*) as count FROM pragma_table_info('messages')
+ WHERE name IN ('thinking_content', 'thinking_signature')
+`).get();
+
+if (hasMessageThinking.count < 2) {
+ console.log('Adding thinking columns to messages table...');
+ db.exec(`
+ ALTER TABLE messages ADD COLUMN thinking_content TEXT DEFAULT NULL;
+ ALTER TABLE messages ADD COLUMN thinking_signature TEXT DEFAULT NULL;
+ `);
+}
+```
+
+---
+
+## 4. Architecture Frontend
+
+### 4.1 Interface Utilisateur
+
+#### Nouveau composant: `ThinkingBlock`
+
+**Fichier**: `src/components/ThinkingBlock.jsx`
+
+```jsx
+import React, { useState } from 'react';
+
+function ThinkingBlock({ thinking, signature, isStreaming }) {
+ const [isExpanded, setIsExpanded] = useState(false);
+
+ return (
+
+ {/* Header avec toggle */}
+
+
+ {/* Contenu thinking (collapsible) */}
+ {isExpanded && (
+
+ {thinking || 'Thinking in progress...'}
+
+ )}
+
+ );
+}
+
+export default ThinkingBlock;
+```
+
+#### Modifications dans `src/App.jsx`
+
+**1. État pour thinking dans Message Component**:
+
+```jsx
+function Message({ message, isStreaming }) {
+ const [thinkingContent, setThinkingContent] = useState(message.thinking_content || '');
+ const [isThinkingStreaming, setIsThinkingStreaming] = useState(false);
+
+ return (
+
+ {/* Afficher thinking block si présent */}
+ {thinkingContent && (
+
+ )}
+
+ {/* Contenu normal du message */}
+
+ {message.content}
+
+
+ );
+}
+```
+
+**2. Settings Panel - Ajouter contrôles thinking**:
+
+```jsx
+function ConversationSettings({ conversation, onUpdate }) {
+ const [settings, setSettings] = useState(JSON.parse(conversation.settings || '{}'));
+
+ return (
+
+ {/* Existing settings */}
+
+
+
+
+
+ {/* Nouveau: Extended Thinking Toggle */}
+
+
+
+ Enable enhanced reasoning for complex tasks
+
+
+
+ {/* Thinking Budget (si thinking activé) */}
+ {settings.enableThinking && (
+
+
+
{
+ const newSettings = {
+ ...settings,
+ thinkingBudgetTokens: parseInt(e.target.value)
+ };
+ setSettings(newSettings);
+ onUpdate(newSettings);
+ }}
+ className="w-full"
+ />
+
+ 1K tokens
+ {(settings.thinkingBudgetTokens || 10000).toLocaleString()} tokens
+ 32K tokens
+
+
+ Higher budgets enable more thorough analysis
+
+
+ )}
+
+ );
+}
+```
+
+**3. Streaming Handler - Gérer thinking deltas**:
+
+```jsx
+async function sendMessage(content) {
+ // ... existing code ...
+
+ const eventSource = new EventSource(`${API_BASE}/conversations/${conversationId}/messages`);
+
+ let currentThinking = '';
+ let currentContent = '';
+ let isInThinkingBlock = false;
+
+ eventSource.addEventListener('message', (event) => {
+ const data = JSON.parse(event.data);
+
+ switch (data.type) {
+ case 'thinking_start':
+ isInThinkingBlock = true;
+ currentThinking = '';
+ setIsThinkingStreaming(true);
+ break;
+
+ case 'thinking':
+ currentThinking += data.text;
+ // Update thinking content in real-time
+ setThinkingContent(currentThinking);
+ break;
+
+ case 'thinking_stop':
+ isInThinkingBlock = false;
+ setIsThinkingStreaming(false);
+ break;
+
+ case 'content':
+ currentContent += data.text;
+ // Update message content
+ setMessageContent(currentContent);
+ break;
+
+ case 'done':
+ eventSource.close();
+ // Save message with thinking
+ saveMessage({
+ content: currentContent,
+ thinking_content: currentThinking,
+ thinking_signature: data.thinking_signature
+ });
+ break;
+ }
+ });
+}
+```
+
+### 4.2 Indicateurs Visuels
+
+#### Badge "Thinking Enabled" dans conversation list
+
+```jsx
+function ConversationListItem({ conversation }) {
+ const settings = JSON.parse(conversation.settings || '{}');
+
+ return (
+
+
{conversation.title}
+
+ {/* Badge thinking */}
+ {settings.enableThinking && (
+
+
+ Thinking
+
+ )}
+
+ );
+}
+```
+
+---
+
+## 5. Gestion du Streaming
+
+### 5.1 Events Sequence
+
+```
+User: "Solve this complex math problem..."
+
+Event 1: thinking_start
+ → Show thinking block with loading animation
+
+Event 2-N: thinking deltas
+ → Update thinking content incrementally
+ → Show typing animation
+
+Event N+1: thinking_stop (implicit with content_block_stop)
+ → Stop thinking animation
+ → Mark thinking complete
+
+Event N+2: content_start
+ → Start showing answer
+
+Event N+3-M: content deltas
+ → Stream answer text
+
+Event M+1: done
+ → Save complete message with thinking + content
+```
+
+### 5.2 Error Handling
+
+**Timeout pour thinking**:
+```javascript
+const THINKING_TIMEOUT = 120000; // 2 minutes
+
+let thinkingTimeout = setTimeout(() => {
+ console.warn('[Thinking] Timeout reached');
+ res.write(`data: ${JSON.stringify({
+ type: 'thinking_timeout',
+ message: 'Thinking process is taking longer than expected...'
+ })}\n\n`);
+}, THINKING_TIMEOUT);
+
+// Clear timeout when thinking completes
+stream.on('content_block_stop', () => {
+ clearTimeout(thinkingTimeout);
+});
+```
+
+**Redacted thinking blocks**:
+```javascript
+if (event.content_block.type === 'redacted_thinking') {
+ console.log('[Thinking] Redacted thinking block detected');
+ res.write(`data: ${JSON.stringify({
+ type: 'thinking_redacted',
+ message: 'Some reasoning has been encrypted for safety'
+ })}\n\n`);
+}
+```
+
+---
+
+## 6. Compatibilité avec Tools
+
+### 6.1 Préservation des Thinking Blocks
+
+**Important**: Lors de l'utilisation de tools avec thinking, il faut préserver les thinking blocks:
+
+```javascript
+// Quand Claude utilise un tool
+if (finalMessage.stop_reason === 'tool_use') {
+ // Extraire tous les blocks thinking ET tool_use
+ const thinkingBlocks = finalMessage.content.filter(b =>
+ b.type === 'thinking' || b.type === 'redacted_thinking'
+ );
+ const toolUseBlocks = finalMessage.content.filter(b =>
+ b.type === 'tool_use'
+ );
+
+ // Ajouter à la conversation
+ conversationMessages.push({
+ role: 'assistant',
+ content: [...thinkingBlocks, ...toolUseBlocks]
+ });
+
+ // Exécuter tools
+ const toolResults = await processToolCalls(toolUseBlocks);
+
+ // Continuer avec les résultats
+ conversationMessages.push({
+ role: 'user',
+ content: toolResults
+ });
+}
+```
+
+### 6.2 Interleaved Thinking (Beta)
+
+Pour activer le thinking entre les tool calls:
+
+```javascript
+// Ajouter le beta header
+const response = await anthropic.messages.create({
+ model: 'claude-opus-4-5',
+ thinking: { type: 'enabled', budget_tokens: 20000 },
+ tools: memoryTools,
+ messages: conversationMessages
+}, {
+ headers: {
+ 'anthropic-beta': 'interleaved-thinking-2025-05-14'
+ }
+});
+```
+
+---
+
+## 7. Pricing & Token Management
+
+### 7.1 Facturation
+
+**Résumé (Claude 4+)**:
+- Input tokens: Tokens de la requête (excluant thinking précédents)
+- Output tokens (facturés): Tokens thinking originaux complets
+- Output tokens (visibles): Tokens thinking résumés affichés
+- Pas de charge: Tokens utilisés pour générer le résumé
+
+**Important**: Le nombre de tokens facturés ≠ tokens visibles dans la réponse.
+
+### 7.2 Token Tracking
+
+**Backend - Logging détaillé**:
+
+```javascript
+// Après réponse avec thinking
+console.log('[Thinking Tokens]', {
+ input_tokens: response.usage.input_tokens,
+ output_tokens: response.usage.output_tokens, // Inclut thinking complet
+ visible_thinking_tokens: calculateTokens(thinkingContent), // Thinking résumé
+ text_output_tokens: calculateTokens(textContent)
+});
+
+// Sauvegarder dans usage_tracking
+db.prepare(`
+ INSERT INTO usage_tracking (
+ id, user_id, conversation_id, message_id, model,
+ input_tokens, output_tokens, thinking_tokens, created_at
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
+`).run(
+ uuidv4(), 'default', conversationId, messageId, model,
+ response.usage.input_tokens,
+ response.usage.output_tokens,
+ calculateTokens(thinkingContent), // Pour tracking
+ new Date().toISOString()
+);
+```
+
+**Frontend - Affichage dans usage stats**:
+
+```jsx
+function UsageStats({ conversation }) {
+ return (
+
+
+
+ {conversation.token_count.toLocaleString()}
+
+
+ {conversation.thinking_tokens > 0 && (
+ <>
+
+
+ {conversation.thinking_tokens.toLocaleString()}
+
+
+ Thinking tokens are summarized but billed at full rate
+
+ >
+ )}
+
+ );
+}
+```
+
+---
+
+## 8. Best Practices
+
+### 8.1 Quand activer thinking
+
+**Recommandé pour**:
+- ✅ Problèmes mathématiques complexes
+- ✅ Analyse de code et debugging
+- ✅ Raisonnement logique multi-étapes
+- ✅ Analyse approfondie de documents
+- ✅ Tâches nécessitant planification
+
+**Pas nécessaire pour**:
+- ❌ Questions simples
+- ❌ Tâches créatives (écriture, brainstorming)
+- ❌ Conversations courtes
+- ❌ Réponses rapides
+
+### 8.2 Budget Recommendations
+
+| Type de tâche | Budget recommandé |
+|---------------|-------------------|
+| Calculs simples | 1,024 - 4,096 tokens |
+| Analyse standard | 4,096 - 10,000 tokens |
+| Problèmes complexes | 10,000 - 16,000 tokens |
+| Tâches très complexes | 16,000 - 32,000 tokens |
+| Recherche approfondie | 32,000+ tokens (batch) |
+
+**Note**: Au-delà de 32K tokens, utiliser batch processing pour éviter les timeouts.
+
+### 8.3 UI/UX Guidelines
+
+1. **Visibility**: Thinking blocks doivent être collapsibles par défaut
+2. **Feedback**: Montrer animation pendant le thinking streaming
+3. **Transparency**: Indiquer clairement quand thinking est actif
+4. **Performance**: Thinking peut augmenter le temps de réponse de 2-5x
+5. **Settings**: Permettre d'activer/désactiver par conversation
+
+---
+
+## 9. Plan d'Implémentation
+
+### Phase 1: Backend Core (2-3h)
+- [ ] Modifier `server/routes/claude.js` pour supporter thinking parameter
+- [ ] Modifier `server/routes/messages.js` pour streaming thinking
+- [ ] Ajouter colonnes DB pour thinking storage
+- [ ] Migration base de données
+- [ ] Tests API avec thinking enabled
+
+### Phase 2: Frontend UI (3-4h)
+- [ ] Créer composant `ThinkingBlock.jsx`
+- [ ] Intégrer thinking display dans messages
+- [ ] Ajouter toggle thinking dans settings
+- [ ] Ajouter thinking budget slider
+- [ ] Tests visuels et UX
+
+### Phase 3: Streaming & Real-time (2-3h)
+- [ ] Implémenter thinking_delta handling
+- [ ] Animations de streaming
+- [ ] Gestion des timeouts
+- [ ] Error handling pour redacted thinking
+- [ ] Tests de streaming
+
+### Phase 4: Tools Integration (2h)
+- [ ] Préservation thinking blocks avec tools
+- [ ] Tests thinking + memory tools
+- [ ] Tests thinking + autres tools futurs
+
+### Phase 5: Polish & Optimization (2h)
+- [ ] Token tracking et logging
+- [ ] Usage analytics pour thinking
+- [ ] Documentation utilisateur
+- [ ] Performance optimization
+- [ ] Tests end-to-end
+
+### Phase 6: Testing & Deployment (1-2h)
+- [ ] Tests avec différents modèles
+- [ ] Tests avec différents budgets
+- [ ] Tests cas d'edge (redacted, timeouts)
+- [ ] Commit et push
+- [ ] Documentation finale
+
+**Temps total estimé**: 12-16 heures
+
+---
+
+## 10. Exemples de Code Complets
+
+### 10.1 Exemple Backend Complet
+
+```javascript
+// server/routes/messages.js - POST /:conversationId/messages
+
+router.post('/:conversationId/messages', async (req, res) => {
+ const db = getDatabase();
+ const { conversationId } = req.params;
+ const { content, images } = req.body;
+
+ // Validate conversation exists
+ const conversation = db.prepare('SELECT * FROM conversations WHERE id = ? AND is_deleted = 0')
+ .get(conversationId);
+
+ if (!conversation) {
+ return res.status(404).json({ error: { message: 'Conversation not found', status: 404 } });
+ }
+
+ // Set up SSE headers
+ res.setHeader('Content-Type', 'text/event-stream');
+ res.setHeader('Cache-Control', 'no-cache');
+ res.setHeader('Connection', 'keep-alive');
+
+ // Parse settings with thinking support
+ const settings = JSON.parse(conversation.settings || '{}');
+ const model = conversation.model || 'claude-sonnet-4-5-20250929';
+ const temperature = settings.temperature || 1;
+ const maxTokens = settings.maxTokens || 4096;
+ const enableThinking = settings.enableThinking || false;
+ const thinkingBudgetTokens = settings.thinkingBudgetTokens || 10000;
+ const enableMemoryTools = true;
+
+ // Save user message
+ const userMessageId = uuidv4();
+ const now = new Date().toISOString();
+
+ db.prepare(`
+ INSERT INTO messages (id, conversation_id, role, content, created_at, images)
+ VALUES (?, ?, ?, ?, ?, ?)
+ `).run(userMessageId, conversationId, 'user', content, now, JSON.stringify(images || []));
+
+ // Get conversation history
+ const dbMessages = db.prepare(`
+ SELECT role, content, images FROM messages
+ WHERE conversation_id = ?
+ ORDER BY created_at ASC
+ `).all(conversationId);
+
+ // Format messages for Claude API
+ const apiMessages = dbMessages.map(m => ({
+ role: m.role,
+ content: m.content
+ }));
+
+ // Get tools and system prompt
+ const tools = enableMemoryTools ? getMemoryTools() : [];
+ const systemPrompt = buildSystemPrompt(
+ getGlobalCustomInstructions(),
+ getProjectCustomInstructions(conversation.project_id),
+ enableMemoryTools
+ );
+
+ // Tracking variables
+ const assistantMessageId = uuidv4();
+ let fullThinkingContent = '';
+ let thinkingSignature = '';
+ let fullContent = '';
+ let totalInputTokens = 0;
+ let totalOutputTokens = 0;
+
+ try {
+ // Build request options
+ const requestOptions = {
+ model,
+ max_tokens: maxTokens,
+ temperature,
+ messages: apiMessages
+ };
+
+ if (systemPrompt) {
+ requestOptions.system = systemPrompt;
+ }
+
+ if (tools.length > 0) {
+ requestOptions.tools = tools;
+ }
+
+ // Add thinking if enabled
+ if (enableThinking) {
+ requestOptions.thinking = {
+ type: 'enabled',
+ budget_tokens: thinkingBudgetTokens
+ };
+ console.log(`[Messages] Extended thinking enabled with budget: ${thinkingBudgetTokens}`);
+ }
+
+ // Create streaming response
+ const stream = await anthropic.messages.stream(requestOptions);
+
+ let isInThinkingBlock = false;
+ let currentBlockIndex = -1;
+
+ // Stream events to client
+ for await (const event of stream) {
+ if (event.type === 'content_block_start') {
+ currentBlockIndex = event.index;
+
+ if (event.content_block.type === 'thinking') {
+ isInThinkingBlock = true;
+ console.log('[Messages] Thinking block started');
+ res.write(`data: ${JSON.stringify({
+ type: 'thinking_start',
+ index: currentBlockIndex
+ })}\n\n`);
+ } else if (event.content_block.type === 'tool_use') {
+ console.log(`[Messages] Tool use requested: ${event.content_block.name}`);
+ res.write(`data: ${JSON.stringify({
+ type: 'tool_use',
+ tool: event.content_block.name,
+ id: event.content_block.id
+ })}\n\n`);
+ }
+ } else if (event.type === 'content_block_delta') {
+ if (event.delta.type === 'thinking_delta') {
+ fullThinkingContent += event.delta.thinking;
+ res.write(`data: ${JSON.stringify({
+ type: 'thinking',
+ text: event.delta.thinking
+ })}\n\n`);
+ } else if (event.delta.type === 'text_delta') {
+ fullContent += event.delta.text;
+ res.write(`data: ${JSON.stringify({
+ type: 'content',
+ text: event.delta.text
+ })}\n\n`);
+ } else if (event.delta.type === 'signature_delta') {
+ thinkingSignature += event.delta.signature;
+ }
+ } else if (event.type === 'content_block_stop') {
+ if (isInThinkingBlock) {
+ isInThinkingBlock = false;
+ console.log('[Messages] Thinking block completed');
+ res.write(`data: ${JSON.stringify({
+ type: 'thinking_stop',
+ index: currentBlockIndex
+ })}\n\n`);
+ }
+ } else if (event.type === 'message_delta') {
+ if (event.usage) {
+ totalInputTokens += event.usage.input_tokens || 0;
+ totalOutputTokens += event.usage.output_tokens || 0;
+ }
+ }
+ }
+
+ // Get final message
+ const finalMessage = await stream.finalMessage();
+ totalInputTokens = finalMessage.usage?.input_tokens || totalInputTokens;
+ totalOutputTokens = finalMessage.usage?.output_tokens || totalOutputTokens;
+
+ // Save assistant message with thinking
+ const assistantNow = new Date().toISOString();
+ db.prepare(`
+ INSERT INTO messages (
+ id, conversation_id, role, content,
+ thinking_content, thinking_signature,
+ created_at, tokens, finish_reason
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
+ `).run(
+ assistantMessageId, conversationId, 'assistant', fullContent,
+ fullThinkingContent || null, thinkingSignature || null,
+ assistantNow, totalOutputTokens, finalMessage.stop_reason
+ );
+
+ // Update conversation
+ db.prepare(`
+ UPDATE conversations
+ SET last_message_at = ?, updated_at = ?,
+ message_count = message_count + 2,
+ token_count = token_count + ?
+ WHERE id = ?
+ `).run(assistantNow, assistantNow, totalInputTokens + totalOutputTokens, conversationId);
+
+ // Track usage
+ db.prepare(`
+ INSERT INTO usage_tracking (
+ id, user_id, conversation_id, message_id, model,
+ input_tokens, output_tokens, created_at
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
+ `).run(
+ uuidv4(), 'default', conversationId, assistantMessageId, model,
+ totalInputTokens, totalOutputTokens, assistantNow
+ );
+
+ // Send done event
+ res.write(`data: ${JSON.stringify({
+ type: 'done',
+ id: assistantMessageId,
+ model: finalMessage.model,
+ stopReason: finalMessage.stop_reason,
+ usage: {
+ inputTokens: totalInputTokens,
+ outputTokens: totalOutputTokens
+ },
+ thinkingTokens: fullThinkingContent.length > 0 ?
+ Math.ceil(fullThinkingContent.length / 4) : 0
+ })}\n\n`);
+
+ res.end();
+
+ } catch (error) {
+ console.error('Claude API stream error:', error);
+ res.write(`data: ${JSON.stringify({
+ type: 'error',
+ message: error.message
+ })}\n\n`);
+ res.end();
+ }
+});
+```
+
+### 10.2 Exemple Frontend Complet
+
+```jsx
+// src/App.jsx - Message Component with Thinking
+
+function Message({ message, isStreaming }) {
+ const [thinkingContent, setThinkingContent] = useState(message.thinking_content || '');
+ const [isThinkingExpanded, setIsThinkingExpanded] = useState(false);
+ const [isThinkingStreaming, setIsThinkingStreaming] = useState(false);
+
+ return (
+
+ {/* Thinking Block (si présent) */}
+ {thinkingContent && message.role === 'assistant' && (
+
+ {/* Header */}
+
+
+ {/* Thinking Content (collapsible) */}
+ {isThinkingExpanded && (
+
+
+ {thinkingContent || (
+
+ Thinking in progress...
+
+ )}
+
+
+ {/* Stats footer */}
+
+
+ ~{Math.ceil(thinkingContent.length / 4)} tokens
+
+
+ Summarized for display
+
+
+
+ )}
+
+ )}
+
+ {/* Message Content */}
+
+ {message.content}
+
+
+ );
+}
+
+// Streaming handler avec thinking support
+async function sendMessage(conversationId, content) {
+ const response = await fetch(`${API_BASE}/conversations/${conversationId}/messages`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ content })
+ });
+
+ const reader = response.body.getReader();
+ const decoder = new TextDecoder();
+
+ let currentThinking = '';
+ let currentContent = '';
+ let isInThinkingBlock = false;
+ let messageId = null;
+
+ // Create temporary message
+ const tempMessage = {
+ id: 'temp-' + Date.now(),
+ role: 'assistant',
+ content: '',
+ thinking_content: '',
+ isStreaming: true
+ };
+
+ setMessages(prev => [...prev, tempMessage]);
+
+ while (true) {
+ const { done, value } = await reader.read();
+ if (done) break;
+
+ const chunk = decoder.decode(value);
+ const lines = chunk.split('\n');
+
+ for (const line of lines) {
+ if (!line.startsWith('data: ')) continue;
+
+ try {
+ const data = JSON.parse(line.slice(6));
+
+ switch (data.type) {
+ case 'thinking_start':
+ isInThinkingBlock = true;
+ setMessages(prev => prev.map(m =>
+ m.id === tempMessage.id
+ ? { ...m, isThinkingStreaming: true }
+ : m
+ ));
+ break;
+
+ case 'thinking':
+ currentThinking += data.text;
+ setMessages(prev => prev.map(m =>
+ m.id === tempMessage.id
+ ? { ...m, thinking_content: currentThinking }
+ : m
+ ));
+ break;
+
+ case 'thinking_stop':
+ isInThinkingBlock = false;
+ setMessages(prev => prev.map(m =>
+ m.id === tempMessage.id
+ ? { ...m, isThinkingStreaming: false }
+ : m
+ ));
+ break;
+
+ case 'content':
+ currentContent += data.text;
+ setMessages(prev => prev.map(m =>
+ m.id === tempMessage.id
+ ? { ...m, content: currentContent }
+ : m
+ ));
+ break;
+
+ case 'done':
+ messageId = data.id;
+ // Update with final message
+ setMessages(prev => prev.map(m =>
+ m.id === tempMessage.id
+ ? {
+ id: messageId,
+ role: 'assistant',
+ content: currentContent,
+ thinking_content: currentThinking,
+ isStreaming: false,
+ isThinkingStreaming: false,
+ usage: data.usage
+ }
+ : m
+ ));
+ break;
+
+ case 'error':
+ console.error('Streaming error:', data.message);
+ setMessages(prev => prev.filter(m => m.id !== tempMessage.id));
+ alert('Error: ' + data.message);
+ break;
+ }
+ } catch (e) {
+ console.error('Error parsing SSE data:', e);
+ }
+ }
+ }
+}
+```
+
+---
+
+## 11. Testing Checklist
+
+### 11.1 Tests Fonctionnels
+
+- [ ] Thinking activé pour conversation → blocs thinking apparaissent
+- [ ] Thinking désactivé → pas de blocs thinking
+- [ ] Streaming thinking fonctionne en temps réel
+- [ ] Toggle thinking dans settings fonctionne
+- [ ] Budget slider fonctionne (1K-32K)
+- [ ] Thinking blocks sont collapsibles
+- [ ] Thinking blocks persistent après refresh
+- [ ] Thinking + memory tools fonctionnent ensemble
+- [ ] Multiple thinking blocks dans une réponse
+- [ ] Redacted thinking est géré correctement
+
+### 11.2 Tests Edge Cases
+
+- [ ] Thinking timeout (>2 min) géré gracefully
+- [ ] Erreurs réseau pendant thinking stream
+- [ ] Thinking avec très grand budget (>32K)
+- [ ] Thinking avec petit budget (1K)
+- [ ] Conversation avec 100+ messages et thinking
+- [ ] Regenerate avec thinking activé
+- [ ] Edit message avec thinking
+- [ ] Export conversation avec thinking
+
+### 11.3 Tests Performance
+
+- [ ] Temps de réponse thinking vs non-thinking
+- [ ] Mémoire utilisée avec thinking streaming
+- [ ] Database performance avec thinking storage
+- [ ] UI responsive pendant thinking
+- [ ] Multiple conversations avec thinking simultanées
+
+---
+
+## 12. Documentation Utilisateur
+
+### Guide Rapide
+
+**Qu'est-ce que Extended Thinking?**
+
+Extended Thinking permet à Claude de "montrer son travail" en exposant son processus de raisonnement étape par étape avant de donner sa réponse finale. Particulièrement utile pour:
+- Problèmes mathématiques complexes
+- Analyse de code approfondie
+- Raisonnement logique multi-étapes
+- Planification de tâches complexes
+
+**Comment l'activer?**
+
+1. Ouvrir les paramètres de conversation (icône ⚙️)
+2. Activer "Extended Thinking"
+3. Ajuster le budget si nécessaire (10K par défaut)
+4. Commencer à discuter
+
+**Interpréter les blocs de thinking**
+
+- 🧠 **Thinking blocks** (bleu): Processus de réflexion de Claude
+- Cliquer pour expand/collapse
+- Contenu est résumé mais bille au tarif complet
+- Peut augmenter le temps de réponse de 2-5x
+
+**Quand l'utiliser?**
+
+✅ **OUI**: Calculs, code, analyse, logique complexe
+❌ **NON**: Questions simples, chat rapide, créativité
+
+---
+
+## 13. Notes Importantes
+
+### 13.1 Limitations
+
+1. **Incompatibilités**:
+ - ❌ Pas compatible avec `temperature` custom ou `top_k`
+ - ❌ Pas de pre-fill responses avec thinking
+ - ❌ Pas de forced tool use (`tool_choice: "any"`)
+ - ✅ Compatible avec `top_p` (0.95-1)
+
+2. **Context Window**:
+ - Thinking blocks précédents retirés automatiquement
+ - Token budget thinking compte vers `max_tokens`
+ - Formule: `context = current_input + (thinking + encrypted + output)`
+
+3. **Caching**:
+ - Changer thinking parameters invalide message cache
+ - System prompt reste en cache
+ - Thinking blocks comptent comme input tokens en cache
+
+### 13.2 Modèles Spécifiques
+
+**Claude Opus 4.5** (unique):
+- Préserve thinking blocks par défaut
+- Meilleure optimization cache
+- Économies de tokens sur multi-turn
+
+**Claude 3.7** (déprécié):
+- Retourne thinking COMPLET (non résumé)
+- Tokens visibles = tokens facturés
+- Migration vers Claude 4+ recommandée
+
+---
+
+## Annexes
+
+### A. Structure de fichiers complète
+
+```
+generations/my_project/
+├── server/
+│ ├── routes/
+│ │ ├── claude.js # Modifié: thinking support
+│ │ └── messages.js # Modifié: thinking streaming
+│ ├── db/
+│ │ └── index.js # Modifié: thinking columns migration
+│ └── config/
+│ └── thinkingDefaults.js # Nouveau: configuration thinking
+├── src/
+│ ├── components/
+│ │ └── ThinkingBlock.jsx # Nouveau: composant thinking
+│ ├── App.jsx # Modifié: thinking UI integration
+│ └── utils/
+│ └── thinkingHelpers.js # Nouveau: helpers thinking
+└── prompts/
+ └── extended_thinking_spec.md # Cette spec
+```
+
+### B. Variables d'environnement
+
+Aucune nouvelle variable nécessaire. Extended Thinking fonctionne avec les credentials Anthropic existants.
+
+### C. Compatibilité navigateurs
+
+Extended Thinking utilise EventSource (SSE) qui est supporté par:
+- ✅ Chrome/Edge 79+
+- ✅ Firefox 65+
+- ✅ Safari 13+
+- ❌ IE11 (non supporté)
+
+---
+
+**Fin de la spécification Extended Thinking**
+
+Version: 1.0
+Date: 2025-12-18
+Auteur: Claude Sonnet 4.5