@boostecom/provider 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +90 -0
  2. package/dist/index.cjs +2522 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.cts +848 -0
  5. package/dist/index.d.ts +848 -0
  6. package/dist/index.js +2484 -0
  7. package/dist/index.js.map +1 -0
  8. package/docs/content/README.md +337 -0
  9. package/docs/content/agent-teams.mdx +324 -0
  10. package/docs/content/api.mdx +757 -0
  11. package/docs/content/best-practices.mdx +624 -0
  12. package/docs/content/examples.mdx +675 -0
  13. package/docs/content/guide.mdx +516 -0
  14. package/docs/content/index.mdx +99 -0
  15. package/docs/content/installation.mdx +246 -0
  16. package/docs/content/skills.mdx +548 -0
  17. package/docs/content/troubleshooting.mdx +588 -0
  18. package/docs/examples/README.md +499 -0
  19. package/docs/examples/abort-signal.ts +125 -0
  20. package/docs/examples/agent-teams.ts +122 -0
  21. package/docs/examples/basic-usage.ts +73 -0
  22. package/docs/examples/check-cli.ts +51 -0
  23. package/docs/examples/conversation-history.ts +69 -0
  24. package/docs/examples/custom-config.ts +90 -0
  25. package/docs/examples/generate-object-constraints.ts +209 -0
  26. package/docs/examples/generate-object.ts +211 -0
  27. package/docs/examples/hooks-callbacks.ts +63 -0
  28. package/docs/examples/images.ts +76 -0
  29. package/docs/examples/integration-test.ts +241 -0
  30. package/docs/examples/limitations.ts +150 -0
  31. package/docs/examples/logging-custom-logger.ts +99 -0
  32. package/docs/examples/logging-default.ts +55 -0
  33. package/docs/examples/logging-disabled.ts +74 -0
  34. package/docs/examples/logging-verbose.ts +64 -0
  35. package/docs/examples/long-running-tasks.ts +179 -0
  36. package/docs/examples/message-injection.ts +210 -0
  37. package/docs/examples/mid-stream-injection.ts +126 -0
  38. package/docs/examples/run-all-examples.sh +48 -0
  39. package/docs/examples/sdk-tools-callbacks.ts +49 -0
  40. package/docs/examples/skills-discovery.ts +144 -0
  41. package/docs/examples/skills-management.ts +140 -0
  42. package/docs/examples/stream-object.ts +80 -0
  43. package/docs/examples/streaming.ts +52 -0
  44. package/docs/examples/structured-output-repro.ts +227 -0
  45. package/docs/examples/tool-management.ts +215 -0
  46. package/docs/examples/tool-streaming.ts +132 -0
  47. package/docs/examples/zod4-compatibility-test.ts +290 -0
  48. package/docs/src/claude-code-language-model.test.ts +3883 -0
  49. package/docs/src/claude-code-language-model.ts +2586 -0
  50. package/docs/src/claude-code-provider.test.ts +97 -0
  51. package/docs/src/claude-code-provider.ts +179 -0
  52. package/docs/src/convert-to-claude-code-messages.images.test.ts +104 -0
  53. package/docs/src/convert-to-claude-code-messages.test.ts +193 -0
  54. package/docs/src/convert-to-claude-code-messages.ts +419 -0
  55. package/docs/src/errors.test.ts +213 -0
  56. package/docs/src/errors.ts +216 -0
  57. package/docs/src/index.test.ts +49 -0
  58. package/docs/src/index.ts +98 -0
  59. package/docs/src/logger.integration.test.ts +164 -0
  60. package/docs/src/logger.test.ts +184 -0
  61. package/docs/src/logger.ts +65 -0
  62. package/docs/src/map-claude-code-finish-reason.test.ts +120 -0
  63. package/docs/src/map-claude-code-finish-reason.ts +60 -0
  64. package/docs/src/mcp-helpers.test.ts +71 -0
  65. package/docs/src/mcp-helpers.ts +123 -0
  66. package/docs/src/message-injection.test.ts +460 -0
  67. package/docs/src/types.ts +447 -0
  68. package/docs/src/validation.test.ts +558 -0
  69. package/docs/src/validation.ts +360 -0
  70. package/package.json +124 -0
@@ -0,0 +1,624 @@
1
+ ---
2
+ title: Best Practices
3
+ description: Conseils et bonnes pratiques pour utiliser le provider Claude Code efficacement
4
+ ---
5
+
6
+ # Best Practices
7
+
8
+ Ce guide présente les meilleures pratiques pour utiliser le provider Claude Code de manière efficace, sécurisée et performante.
9
+
10
+ ## Choix du modèle
11
+
12
+ ### Adapter le modèle à la tâche
13
+
14
+ ```typescript
15
+ // ✅ Haiku pour tâches simples et rapides
16
+ const quickTask = claudeCode('haiku');
17
+ await generateText({
18
+ model: quickTask,
19
+ prompt: 'Résume ce texte en une phrase',
20
+ });
21
+
22
+ // ✅ Sonnet pour usage général (recommandé)
23
+ const balanced = claudeCode('sonnet');
24
+ await generateText({
25
+ model: balanced,
26
+ prompt: 'Analyse ce code et suggère des améliorations',
27
+ });
28
+
29
+ // ✅ Opus pour tâches complexes uniquement
30
+ const complex = claudeCode('opus');
31
+ await generateText({
32
+ model: complex,
33
+ prompt: 'Conçois l\'architecture complète d\'un système distribué...',
34
+ });
35
+ ```
36
+
37
+ **Règle d'or** : Commencez par Haiku, passez à Sonnet si nécessaire, réservez Opus aux tâches vraiment complexes.
38
+
39
+ ## Gestion du contexte
40
+
41
+ ### Maintenir l'historique efficacement
42
+
43
+ ```typescript
44
+ import type { CoreMessage } from 'ai';
45
+
46
+ // ✅ Bon : Historique complet mais raisonnable
47
+ const messages: CoreMessage[] = [];
48
+
49
+ function addMessage(role: 'user' | 'assistant', content: string) {
50
+ messages.push({ role, content });
51
+
52
+ // Limiter à 20 derniers messages pour éviter token overflow
53
+ if (messages.length > 20) {
54
+ messages.splice(0, messages.length - 20);
55
+ }
56
+ }
57
+
58
+ // ❌ Mauvais : Historique illimité
59
+ const unlimitedHistory: CoreMessage[] = [];
60
+ // Peut causer des erreurs de limite de tokens
61
+ ```
62
+
63
+ ### Résumé périodique pour conversations longues
64
+
65
+ ```typescript
66
+ async function summarizeHistory(messages: CoreMessage[]) {
67
+ if (messages.length > 15) {
68
+ const { text } = await generateText({
69
+ model: claudeCode('haiku'), // Haiku suffisant pour résumé
70
+ prompt: `Résume cette conversation en quelques phrases clés:\n${
71
+ messages.map(m => `${m.role}: ${m.content}`).join('\n')
72
+ }`,
73
+ });
74
+
75
+ // Remplacer l'historique par le résumé
76
+ return [
77
+ { role: 'assistant', content: `Résumé: ${text}` },
78
+ ...messages.slice(-5), // Garder les 5 derniers messages
79
+ ];
80
+ }
81
+ return messages;
82
+ }
83
+ ```
84
+
85
+ ## Structured Outputs
86
+
87
+ ### Schémas simples et robustes
88
+
89
+ ```typescript
90
+ import { z } from 'zod';
91
+
92
+ // ✅ Bon : Schéma simple avec descriptions
93
+ const goodSchema = z.object({
94
+ nom: z.string().min(1).max(100),
95
+ age: z.number().int().min(0).max(150),
96
+ email: z.string().describe('Email (ex: user@example.com)'),
97
+ role: z.enum(['admin', 'user', 'guest']),
98
+ });
99
+
100
+ // ❌ Mauvais : Contraintes complexes qui causent fallback
101
+ const badSchema = z.object({
102
+ email: z.string().email(), // format constraint
103
+ url: z.string().url(), // format constraint
104
+ password: z.string().regex(/^(?=.*[A-Z])(?=.*[0-9]).{8,}$/), // lookahead
105
+ });
106
+
107
+ // ✅ Solution : Valider côté client
108
+ const simpleSchema = z.object({
109
+ email: z.string().describe('Email valide'),
110
+ url: z.string().describe('URL complète avec protocole'),
111
+ password: z.string().min(8).describe('8+ caractères, maj et chiffres'),
112
+ });
113
+
114
+ const result = await generateObject({ model, schema: simpleSchema, prompt });
115
+
116
+ // Validation stricte côté client
117
+ const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(result.object.email);
118
+ ```
119
+
120
+ ### Décomposition pour schémas complexes
121
+
122
+ ```typescript
123
+ // ❌ Mauvais : Un seul appel avec schéma énorme
124
+ const hugeSchema = z.object({
125
+ user: z.object({ /* 20 champs */ }),
126
+ company: z.object({ /* 20 champs */ }),
127
+ settings: z.object({ /* 20 champs */ }),
128
+ });
129
+
130
+ // ✅ Bon : Plusieurs appels avec schémas ciblés
131
+ const userSchema = z.object({ /* 10 champs essentiels */ });
132
+ const companySchema = z.object({ /* 10 champs essentiels */ });
133
+
134
+ const user = await generateObject({ model, schema: userSchema, prompt: '...' });
135
+ const company = await generateObject({ model, schema: companySchema, prompt: '...' });
136
+
137
+ const complete = { user: user.object, company: company.object };
138
+ ```
139
+
140
+ ## Sécurité
141
+
142
+ ### Contrôle des outils
143
+
144
+ ```typescript
145
+ // ✅ Bon : Liste blanche explicite
146
+ const safeModel = claudeCode('sonnet', {
147
+ allowedTools: ['Read', 'LS'], // Seulement lecture
148
+ disallowedTools: [
149
+ 'Write',
150
+ 'Edit',
151
+ 'Bash(rm:*)', // Bloquer rm
152
+ 'Bash(sudo:*)', // Bloquer sudo
153
+ ],
154
+ });
155
+
156
+ // ❌ Risqué : Tous les outils sans restriction
157
+ const riskyModel = claudeCode('sonnet', {
158
+ permissionMode: 'bypassPermissions',
159
+ allowDangerouslySkipPermissions: true,
160
+ });
161
+ ```
162
+
163
+ ### Validation des entrées utilisateur
164
+
165
+ ```typescript
166
+ import { z } from 'zod';
167
+
168
+ // ✅ Bon : Validation avant envoi
169
+ const inputSchema = z.object({
170
+ prompt: z.string().min(1).max(5000),
171
+ model: z.enum(['haiku', 'sonnet', 'opus']),
172
+ });
173
+
174
+ async function safeGenerate(userInput: unknown) {
175
+ // Valider l'entrée
176
+ const validated = inputSchema.safeParse(userInput);
177
+
178
+ if (!validated.success) {
179
+ throw new Error('Entrée invalide');
180
+ }
181
+
182
+ return await generateText({
183
+ model: claudeCode(validated.data.model),
184
+ prompt: validated.data.prompt,
185
+ });
186
+ }
187
+
188
+ // ❌ Mauvais : Accepter les entrées sans validation
189
+ async function unsafeGenerate(userInput: any) {
190
+ return await generateText({
191
+ model: claudeCode(userInput.model), // Peut crasher
192
+ prompt: userInput.prompt, // Peut être malicieux
193
+ });
194
+ }
195
+ ```
196
+
197
+ ### Sandboxing en production
198
+
199
+ ```typescript
200
+ // ✅ Bon : Environnement isolé
201
+ const productionModel = claudeCode('sonnet', {
202
+ sandbox: { enabled: true },
203
+ cwd: '/safe/isolated/directory',
204
+ allowedTools: ['Read'], // Minimal
205
+ persistSession: false, // Pas de persistence
206
+ });
207
+
208
+ // ❌ Risqué : Accès complet au système
209
+ const riskyModel = claudeCode('sonnet', {
210
+ cwd: '/',
211
+ allowedTools: ['Bash'], // Accès shell illimité
212
+ });
213
+ ```
214
+
215
+ ## Performance
216
+
217
+ ### Streaming pour grandes réponses
218
+
219
+ ```typescript
220
+ // ✅ Bon : Streaming pour réponses longues
221
+ const result = streamText({
222
+ model: claudeCode('sonnet'),
223
+ prompt: 'Écris un article de 2000 mots...',
224
+ });
225
+
226
+ for await (const chunk of result.textStream) {
227
+ process.stdout.write(chunk); // Affichage progressif
228
+ // Chunk garbage collected après usage
229
+ }
230
+
231
+ // ❌ Mauvais : Attendre la réponse complète
232
+ const result = await generateText({
233
+ model: claudeCode('sonnet'),
234
+ prompt: 'Écris un article de 2000 mots...',
235
+ });
236
+ console.log(result.text); // Tout en mémoire
237
+ ```
238
+
239
+ ### Parallélisation des tâches indépendantes
240
+
241
+ ```typescript
242
+ // ✅ Bon : Exécution parallèle
243
+ const [summary, keywords, sentiment] = await Promise.all([
244
+ generateText({ model: claudeCode('haiku'), prompt: 'Résume: ...' }),
245
+ generateText({ model: claudeCode('haiku'), prompt: 'Mots-clés: ...' }),
246
+ generateText({ model: claudeCode('haiku'), prompt: 'Sentiment: ...' }),
247
+ ]);
248
+
249
+ // ❌ Mauvais : Exécution séquentielle
250
+ const summary = await generateText({ model, prompt: 'Résume: ...' });
251
+ const keywords = await generateText({ model, prompt: 'Mots-clés: ...' });
252
+ const sentiment = await generateText({ model, prompt: 'Sentiment: ...' });
253
+ ```
254
+
255
+ ### Cache des résultats fréquents
256
+
257
+ ```typescript
258
+ import NodeCache from 'node-cache';
259
+
260
+ const cache = new NodeCache({ stdTTL: 3600 }); // 1 heure
261
+
262
+ async function cachedGenerate(prompt: string) {
263
+ // Vérifier le cache
264
+ const cached = cache.get(prompt);
265
+ if (cached) {
266
+ return cached;
267
+ }
268
+
269
+ // Générer si pas en cache
270
+ const { text } = await generateText({
271
+ model: claudeCode('haiku'),
272
+ prompt,
273
+ });
274
+
275
+ // Mettre en cache
276
+ cache.set(prompt, text);
277
+ return text;
278
+ }
279
+ ```
280
+
281
+ ## Gestion d'erreurs
282
+
283
+ ### Pattern robuste avec retry
284
+
285
+ ```typescript
286
+ async function generateWithRetry(
287
+ prompt: string,
288
+ maxRetries = 3
289
+ ): Promise<string> {
290
+ for (let i = 0; i < maxRetries; i++) {
291
+ try {
292
+ const { text } = await generateText({
293
+ model: claudeCode('sonnet'),
294
+ prompt,
295
+ });
296
+ return text;
297
+ } catch (error: any) {
298
+ // Dernière tentative
299
+ if (i === maxRetries - 1) throw error;
300
+
301
+ // Erreur réseau/temporaire
302
+ if (error.code === 'ECONNRESET' || error.code === 'ETIMEDOUT') {
303
+ console.log(`Tentative ${i + 1} échouée, retry...`);
304
+ await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
305
+ continue;
306
+ }
307
+
308
+ // Erreur non recoverable
309
+ throw error;
310
+ }
311
+ }
312
+ throw new Error('Max retries exceeded');
313
+ }
314
+ ```
315
+
316
+ ### Fallback sur modèle plus simple
317
+
318
+ ```typescript
319
+ async function generateWithFallback(prompt: string) {
320
+ try {
321
+ // Essayer Opus
322
+ return await generateText({
323
+ model: claudeCode('opus'),
324
+ prompt,
325
+ });
326
+ } catch (error: any) {
327
+ if (error.message?.includes('rate limit')) {
328
+ // Fallback sur Sonnet si rate limited
329
+ console.warn('Rate limited, fallback sur Sonnet');
330
+ return await generateText({
331
+ model: claudeCode('sonnet'),
332
+ prompt,
333
+ });
334
+ }
335
+ throw error;
336
+ }
337
+ }
338
+ ```
339
+
340
+ ### Timeout approprié
341
+
342
+ ```typescript
343
+ async function generateWithTimeout(prompt: string, timeoutMs = 60000) {
344
+ const controller = new AbortController();
345
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
346
+
347
+ try {
348
+ const result = await generateText({
349
+ model: claudeCode('sonnet'),
350
+ prompt,
351
+ abortSignal: controller.signal,
352
+ });
353
+ clearTimeout(timeoutId);
354
+ return result;
355
+ } catch (error: any) {
356
+ if (error.name === 'AbortError') {
357
+ throw new Error(`Timeout après ${timeoutMs}ms`);
358
+ }
359
+ throw error;
360
+ }
361
+ }
362
+ ```
363
+
364
+ ## Logging et monitoring
365
+
366
+ ### Logging structuré
367
+
368
+ ```typescript
369
+ import type { Logger } from '@boostecom/provider';
370
+
371
+ const structuredLogger: Logger = {
372
+ debug: (msg) => logger.debug({ component: 'claude-code', message: msg }),
373
+ info: (msg) => logger.info({ component: 'claude-code', message: msg }),
374
+ warn: (msg) => logger.warn({ component: 'claude-code', message: msg }),
375
+ error: (msg) => {
376
+ logger.error({ component: 'claude-code', message: msg });
377
+ // Alerter si critique
378
+ if (msg.includes('authentication')) {
379
+ sendAlert('Claude Code auth failed');
380
+ }
381
+ },
382
+ };
383
+
384
+ const model = claudeCode('sonnet', {
385
+ verbose: true,
386
+ logger: structuredLogger,
387
+ });
388
+ ```
389
+
390
+ ### Monitoring des coûts
391
+
392
+ ```typescript
393
+ let totalCost = 0;
394
+ let totalTokens = 0;
395
+
396
+ async function monitoredGenerate(prompt: string) {
397
+ const result = await generateText({
398
+ model: claudeCode('sonnet'),
399
+ prompt,
400
+ });
401
+
402
+ // Tracker usage
403
+ totalTokens += result.usage.totalTokens;
404
+
405
+ // Estimer coût (exemple: $0.003/1K tokens)
406
+ const cost = (result.usage.totalTokens / 1000) * 0.003;
407
+ totalCost += cost;
408
+
409
+ // Logger
410
+ console.log({
411
+ tokens: result.usage.totalTokens,
412
+ cost: cost.toFixed(4),
413
+ totalCost: totalCost.toFixed(4),
414
+ totalTokens,
415
+ });
416
+
417
+ // Alerte si dépassement budget
418
+ if (totalCost > 10) {
419
+ throw new Error('Budget journalier dépassé');
420
+ }
421
+
422
+ return result;
423
+ }
424
+ ```
425
+
426
+ ### Tracking des performances
427
+
428
+ ```typescript
429
+ async function trackedGenerate(prompt: string) {
430
+ const startTime = Date.now();
431
+
432
+ try {
433
+ const result = await generateText({
434
+ model: claudeCode('sonnet'),
435
+ prompt,
436
+ });
437
+
438
+ const duration = Date.now() - startTime;
439
+
440
+ // Envoyer métriques
441
+ metrics.record({
442
+ metric: 'claude_generate_duration',
443
+ value: duration,
444
+ tags: { model: 'sonnet', status: 'success' },
445
+ });
446
+
447
+ return result;
448
+ } catch (error: any) {
449
+ const duration = Date.now() - startTime;
450
+
451
+ metrics.record({
452
+ metric: 'claude_generate_duration',
453
+ value: duration,
454
+ tags: { model: 'sonnet', status: 'error' },
455
+ });
456
+
457
+ throw error;
458
+ }
459
+ }
460
+ ```
461
+
462
+ ## Testing
463
+
464
+ ### Tests unitaires avec mocking
465
+
466
+ ```typescript
467
+ import { vi, describe, it, expect } from 'vitest';
468
+
469
+ // Mock du provider
470
+ vi.mock('@boostecom/provider', () => ({
471
+ claudeCode: vi.fn(() => ({
472
+ provider: 'claude-code',
473
+ modelId: 'sonnet',
474
+ })),
475
+ }));
476
+
477
+ describe('Service avec Claude', () => {
478
+ it('génère une réponse', async () => {
479
+ const mockGenerateText = vi.fn().mockResolvedValue({
480
+ text: 'Réponse mockée',
481
+ usage: { totalTokens: 100 },
482
+ });
483
+
484
+ // Votre logique de test
485
+ const result = await mockGenerateText({
486
+ model: claudeCode('sonnet'),
487
+ prompt: 'Test',
488
+ });
489
+
490
+ expect(result.text).toBe('Réponse mockée');
491
+ });
492
+ });
493
+ ```
494
+
495
+ ### Tests d'intégration
496
+
497
+ ```typescript
498
+ import { describe, it, expect } from 'vitest';
499
+ import { generateText } from 'ai';
500
+ import { claudeCode } from '@boostecom/provider';
501
+
502
+ describe('Intégration Claude Code', () => {
503
+ it('génère du texte réel', async () => {
504
+ const { text } = await generateText({
505
+ model: claudeCode('haiku'), // Haiku pour coût/vitesse
506
+ prompt: 'Dis simplement "OK"',
507
+ });
508
+
509
+ expect(text).toBeTruthy();
510
+ expect(text.toLowerCase()).toContain('ok');
511
+ }, 30000); // Timeout 30s
512
+
513
+ it('génère un objet structuré', async () => {
514
+ const { object } = await generateObject({
515
+ model: claudeCode('haiku'),
516
+ schema: z.object({
517
+ nombre: z.number(),
518
+ }),
519
+ prompt: 'Génère un objet avec nombre = 42',
520
+ });
521
+
522
+ expect(object.nombre).toBe(42);
523
+ }, 30000);
524
+ });
525
+ ```
526
+
527
+ ## Production
528
+
529
+ ### Configuration d'environnement
530
+
531
+ ```typescript
532
+ // config.ts
533
+ const isProd = process.env.NODE_ENV === 'production';
534
+
535
+ export const claudeConfig = {
536
+ model: isProd ? 'sonnet' : 'haiku', // Haiku en dev
537
+ verbose: !isProd, // Logs seulement en dev
538
+ persistSession: !isProd, // Pas de persistence en prod
539
+ sandbox: isProd ? { enabled: true } : undefined,
540
+ maxTurns: isProd ? 5 : 10, // Limiter en prod
541
+ allowedTools: isProd
542
+ ? ['Read', 'LS'] // Minimal en prod
543
+ : ['Read', 'Write', 'Bash'], // Plus permissif en dev
544
+ };
545
+
546
+ // Utilisation
547
+ const model = claudeCode('sonnet', claudeConfig);
548
+ ```
549
+
550
+ ### Rate limiting
551
+
552
+ ```typescript
553
+ import Bottleneck from 'bottleneck';
554
+
555
+ // Limiter à 10 requêtes par minute
556
+ const limiter = new Bottleneck({
557
+ maxConcurrent: 1,
558
+ minTime: 6000, // 6s entre requêtes
559
+ });
560
+
561
+ async function rateLimitedGenerate(prompt: string) {
562
+ return limiter.schedule(async () => {
563
+ return await generateText({
564
+ model: claudeCode('sonnet'),
565
+ prompt,
566
+ });
567
+ });
568
+ }
569
+ ```
570
+
571
+ ### Health checks
572
+
573
+ ```typescript
574
+ import express from 'express';
575
+
576
+ const app = express();
577
+
578
+ app.get('/health', async (req, res) => {
579
+ try {
580
+ // Test simple avec timeout court
581
+ const controller = new AbortController();
582
+ const timeoutId = setTimeout(() => controller.abort(), 5000);
583
+
584
+ await generateText({
585
+ model: claudeCode('haiku'),
586
+ prompt: 'Dis OK',
587
+ abortSignal: controller.signal,
588
+ });
589
+
590
+ clearTimeout(timeoutId);
591
+ res.json({ status: 'healthy', claude: 'ok' });
592
+ } catch (error: any) {
593
+ res.status(503).json({
594
+ status: 'unhealthy',
595
+ claude: 'error',
596
+ message: error.message,
597
+ });
598
+ }
599
+ });
600
+ ```
601
+
602
+ ## Ressources
603
+
604
+ - [Guide d'utilisation](/docs/guide) - Patterns de base
605
+ - [API Reference](/docs/api) - Documentation complète
606
+ - [Exemples](/docs/examples) - Cas d'usage pratiques
607
+ - [Dépannage](/docs/troubleshooting) - Solutions aux problèmes
608
+
609
+ ## Checklist finale
610
+
611
+ Avant de déployer en production :
612
+
613
+ - [ ] Modèle adapté à la tâche (Haiku pour simple, Sonnet pour général)
614
+ - [ ] Outils restreints au minimum nécessaire
615
+ - [ ] Validation des entrées utilisateur
616
+ - [ ] Gestion d'erreurs avec retry
617
+ - [ ] Timeouts appropriés configurés
618
+ - [ ] Logging structuré en place
619
+ - [ ] Monitoring des coûts activé
620
+ - [ ] Tests d'intégration passants
621
+ - [ ] Rate limiting configuré
622
+ - [ ] Health checks implémentés
623
+ - [ ] Secrets sécurisés (pas de hardcoding)
624
+ - [ ] Documentation à jour