@atlashub/smartstack-cli 1.10.2 → 1.12.0

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 (74) hide show
  1. package/.documentation/agents.html +7 -2
  2. package/.documentation/apex.html +7 -2
  3. package/.documentation/business-analyse.html +7 -2
  4. package/.documentation/cli-commands.html +871 -0
  5. package/.documentation/commands.html +7 -2
  6. package/.documentation/efcore.html +7 -2
  7. package/.documentation/gitflow.html +7 -2
  8. package/.documentation/hooks.html +7 -2
  9. package/.documentation/index.html +7 -2
  10. package/.documentation/init.html +7 -2
  11. package/.documentation/installation.html +7 -2
  12. package/.documentation/ralph-loop.html +7 -2
  13. package/.documentation/test-web.html +7 -2
  14. package/dist/index.js +1932 -336
  15. package/dist/index.js.map +1 -1
  16. package/package.json +8 -2
  17. package/templates/agents/efcore/squash.md +67 -31
  18. package/templates/agents/gitflow/finish.md +68 -56
  19. package/templates/commands/business-analyse/0-orchestrate.md +72 -556
  20. package/templates/commands/business-analyse/1-init.md +23 -193
  21. package/templates/commands/business-analyse/2-discover.md +85 -462
  22. package/templates/commands/business-analyse/3-analyse.md +40 -342
  23. package/templates/commands/business-analyse/4-specify.md +72 -537
  24. package/templates/commands/business-analyse/5-validate.md +43 -237
  25. package/templates/commands/business-analyse/6-handoff.md +93 -682
  26. package/templates/commands/business-analyse/7-doc-html.md +45 -544
  27. package/templates/commands/business-analyse/_shared.md +176 -0
  28. package/templates/commands/business-analyse/bug.md +50 -257
  29. package/templates/commands/business-analyse/change-request.md +59 -283
  30. package/templates/commands/business-analyse/hotfix.md +36 -120
  31. package/templates/commands/business-analyse.md +55 -574
  32. package/templates/commands/efcore/_shared.md +206 -0
  33. package/templates/commands/efcore/conflicts.md +39 -201
  34. package/templates/commands/efcore/db-deploy.md +28 -237
  35. package/templates/commands/efcore/db-reset.md +41 -390
  36. package/templates/commands/efcore/db-seed.md +44 -323
  37. package/templates/commands/efcore/db-status.md +31 -210
  38. package/templates/commands/efcore/migration.md +45 -368
  39. package/templates/commands/efcore/rebase-snapshot.md +38 -241
  40. package/templates/commands/efcore/scan.md +35 -204
  41. package/templates/commands/efcore/squash.md +158 -251
  42. package/templates/commands/efcore.md +49 -177
  43. package/templates/commands/gitflow/1-init.md +94 -1318
  44. package/templates/commands/gitflow/10-start.md +86 -990
  45. package/templates/commands/gitflow/11-finish.md +264 -454
  46. package/templates/commands/gitflow/12-cleanup.md +40 -213
  47. package/templates/commands/gitflow/2-status.md +51 -386
  48. package/templates/commands/gitflow/3-commit.md +108 -801
  49. package/templates/commands/gitflow/4-plan.md +42 -13
  50. package/templates/commands/gitflow/5-exec.md +60 -5
  51. package/templates/commands/gitflow/6-abort.md +54 -277
  52. package/templates/commands/gitflow/7-pull-request.md +74 -717
  53. package/templates/commands/gitflow/8-review.md +51 -178
  54. package/templates/commands/gitflow/9-merge.md +74 -404
  55. package/templates/commands/gitflow/_shared.md +196 -0
  56. package/templates/commands/quickstart.md +154 -0
  57. package/templates/commands/ralph-loop/ralph-loop.md +104 -2
  58. package/templates/hooks/hooks.json +13 -0
  59. package/templates/hooks/ralph-mcp-logger.sh +46 -0
  60. package/templates/hooks/ralph-session-end.sh +69 -0
  61. package/templates/ralph/README.md +91 -0
  62. package/templates/ralph/ralph.config.yaml +113 -0
  63. package/templates/scripts/setup-ralph-loop.sh +173 -0
  64. package/templates/skills/_shared.md +117 -0
  65. package/templates/skills/ai-prompt/SKILL.md +87 -654
  66. package/templates/skills/application/SKILL.md +76 -499
  67. package/templates/skills/controller/SKILL.md +38 -165
  68. package/templates/skills/documentation/SKILL.md +2 -1
  69. package/templates/skills/feature-full/SKILL.md +107 -732
  70. package/templates/skills/notification/SKILL.md +85 -474
  71. package/templates/skills/ui-components/SKILL.md +62 -762
  72. package/templates/skills/workflow/SKILL.md +85 -489
  73. package/templates/commands/gitflow/rescue.md +0 -867
  74. package/templates/skills/business-analyse/SKILL.md +0 -191
@@ -16,9 +16,9 @@ description: |
16
16
  > **Architecture:** Prompt + Blocks → Provider + Model → Completion → Schema Validation
17
17
  > Multi-provider: OpenAI, Anthropic (Claude), Azure OpenAI, Google Gemini
18
18
 
19
- ## QUAND CE SKILL S'ACTIVE
19
+ **Référence:** [_shared.md](../_shared.md) pour patterns communs
20
20
 
21
- Claude invoque automatiquement ce skill quand il detecte :
21
+ ## QUAND CE SKILL S'ACTIVE
22
22
 
23
23
  | Declencheur | Exemple |
24
24
  |-------------|---------|
@@ -28,751 +28,184 @@ Claude invoque automatiquement ce skill quand il detecte :
28
28
  | Analyse texte | "Analyse le sentiment des commentaires" |
29
29
  | Mots-cles | "prompt", "GPT", "Claude", "IA", "completion", "LLM" |
30
30
 
31
- ---
32
-
33
- ## ARCHITECTURE IA
31
+ ## FLOW IA
34
32
 
35
33
  ```
36
- ┌─────────────────────────────────────────────────────────────────────────────┐
37
- │ AI COMPLETION FLOW │
38
- ├─────────────────────────────────────────────────────────────────────────────┤
39
- │ │
40
- │ [FEATURE] ─────────────────────────────────────────────────────────────┐ │
41
- │ │ │ │
42
- │ ▼ │ │
43
- │ ┌─────────────────────────────┐ │ │
44
- │ │ IAiCompletionService │ │ │
45
- │ │ ExecutePromptAsync() │ │ │
46
- │ └─────────────┬───────────────┘ │ │
47
- │ │ │ │
48
- │ ┌────────┴────────┐ │ │
49
- │ ▼ ▼ │ │
50
- │ ┌─────────────┐ ┌─────────────────┐ │ │
51
- │ │ Prompt │ │ Provider │ │ │
52
- │ │ + Blocks │ │ Instance │ │ │
53
- │ └──────┬──────┘ └────────┬────────┘ │ │
54
- │ │ │ │ │
55
- │ ▼ ▼ │ │
56
- │ ┌─────────────────────────────────────┐ │ │
57
- │ │ RENDERED PROMPT │ │ │
58
- │ │ System: {{instructions}} │ │ │
59
- │ │ User: {{userInput}} │ │ │
60
- │ └─────────────────┬───────────────────┘ │ │
61
- │ │ │ │
62
- │ ▼ │ │
63
- │ ┌─────────────────────────────────────┐ │ │
64
- │ │ EXTERNAL API │ │ │
65
- │ │ OpenAI / Claude / Azure / Gemini │ │ │
66
- │ └─────────────────┬───────────────────┘ │ │
67
- │ │ │ │
68
- │ ▼ │ │
69
- │ ┌─────────────────────────────────────┐ │ │
70
- │ │ AI RESPONSE │ │ │
71
- │ │ { "content": "...", ... } │ │ │
72
- │ └─────────────────┬───────────────────┘ │ │
73
- │ │ │ │
74
- │ ┌────────────┴────────────┐ │ │
75
- │ ▼ ▼ │ │
76
- │ ┌─────────────┐ ┌─────────────────┐ │ │
77
- │ │ RAW │ │ OutputSchema │ │ │
78
- │ │ Response │ │ Validation │ │ │
79
- │ └─────────────┘ └────────┬────────┘ │ │
80
- │ │ │ │
81
- │ ▼ │ │
82
- │ ┌─────────────────┐ │ │
83
- │ │ Typed Result<T> │ │ │
84
- │ │ + Validation │ │ │
85
- │ └─────────────────┘ │ │
86
- │ │ │
87
- └────────────────────────────────────────────────────────────────────────────┘
34
+ Feature → IAiCompletionService.ExecutePromptAsync()
35
+
36
+ Prompt + Blocks → Provider Instance → External API (OpenAI/Claude/Azure/Gemini)
37
+
38
+ AI Response → OutputSchema Validation → Typed Result<T>
88
39
  ```
89
40
 
90
- ---
91
-
92
41
  ## ENTITES PRINCIPALES
93
42
 
94
- ### AiProvider
95
-
96
- ```csharp
97
- // Providers disponibles (seed data)
98
- - OpenAI (gpt-4o, gpt-4-turbo, gpt-3.5-turbo)
99
- - Anthropic (claude-3-opus, claude-3-sonnet, claude-3-haiku)
100
- - Azure OpenAI (deploiements custom)
101
- - Google (gemini-pro, gemini-1.5-pro)
102
- ```
103
-
104
- ### AiModel
105
-
106
- ```csharp
107
- // Proprietes cles
108
- public string Code { get; } // "gpt-4o"
109
- public string ShortCode { get; } // "GPT4O"
110
- public ModelCategory Category { get; } // TextGeneration, Embedding, etc.
111
- public int ContextWindow { get; } // 128000
112
- public int MaxOutputTokens { get; } // 16384
113
- public decimal InputCostPerMillion { get; }
114
- public decimal OutputCostPerMillion { get; }
115
-
116
- // Capabilities
117
- public bool SupportsVision { get; }
118
- public bool SupportsFunctionCalling { get; }
119
- public bool SupportsStreaming { get; }
120
- ```
43
+ ### AiProvider & AiModel
44
+ - **Providers:** OpenAI, Anthropic, Azure OpenAI, Google
45
+ - **Models:** gpt-4o, claude-3-opus/sonnet/haiku, gemini-pro
46
+ - Properties: Code, ContextWindow, MaxOutputTokens, InputCost, OutputCost, SupportsVision, SupportsStreaming
121
47
 
122
48
  ### AiProviderInstance
49
+ Instance configurée: Code, Name, SystemContext, DefaultModel, MonthlyBudgetLimit, EncryptedApiKey
123
50
 
51
+ ### Prompt & PromptBlock
124
52
  ```csharp
125
- // Instance configuree pour un use-case
126
- public string Code { get; } // "support-assistant"
127
- public string Name { get; } // "Assistant Support"
128
- public string SystemContext { get; } // Prompt systeme personnalise
129
- public string DefaultModel { get; } // "gpt-4o"
130
- public decimal MonthlyBudgetLimit { get; }
131
- public decimal CurrentMonthUsage { get; }
132
-
133
- // Securite
134
- public string EncryptedApiKey { get; } // Cle chiffree
135
- ```
136
-
137
- ### Prompt
138
-
139
- ```csharp
140
- // Structure d'un prompt
141
- public string Code { get; } // "ticket-analyzer"
142
- public string Name { get; } // "Ticket Analyzer"
143
- public string Version { get; } // "1.0.0"
144
- public PromptStatus Status { get; } // Draft, Active, Deprecated
145
- public bool IsTemplate { get; } // Template reutilisable
146
- public Guid? OutputSchemaId { get; } // Schema de validation
147
-
148
- // Blocks = Sections du prompt
149
- public ICollection<PromptBlock> Blocks { get; }
150
- ```
151
-
152
- ### PromptBlock
153
-
154
- ```csharp
155
- // Types de blocks
156
- public enum PromptBlockType
157
- {
158
- System, // Instructions systeme
159
- User, // Message utilisateur
160
- Assistant, // Reponse exemple
161
- Tool, // Definition d'outil
162
- Context, // Contexte additionnel
163
- Examples // Exemples few-shot
164
- }
165
-
166
- // Proprietes
167
- public string Label { get; } // "Instructions"
168
- public string Content { get; } // "Tu es un assistant..."
169
- public int DisplayOrder { get; }
170
- public bool IsRequired { get; }
171
- public string Condition { get; } // Condition d'inclusion
53
+ // Prompt: Code, Name, Version, Status, IsTemplate, OutputSchemaId, Blocks
54
+ // PromptBlockType: System, User, Assistant, Tool, Context, Examples
55
+ // Block: Label, Content, DisplayOrder, IsRequired, Condition
172
56
  ```
173
57
 
174
58
  ### OutputSchema
59
+ JSON Schema pour validation: Code, Name, JsonSchema, DotNetType
175
60
 
176
- ```csharp
177
- // Schema JSON pour validation
178
- public string Code { get; } // "ticket-analysis"
179
- public string Name { get; } // "Ticket Analysis Schema"
180
- public string JsonSchema { get; } // JSON Schema valide
181
- public string DotNetType { get; } // "SmartStack.Application.AI.TicketAnalysisResult"
182
- ```
183
-
184
- ---
185
-
186
- ## WORKFLOW INTEGRATION IA
187
-
188
- ### ETAPE 1: Definir le Use Case
61
+ ## WORKFLOW INTEGRATION
189
62
 
63
+ ### 1. Definir le Use Case
190
64
  | Question | Impact |
191
65
  |----------|--------|
192
- | Quel type de contenu generer ? | Choix du modele |
193
- | Reponse structuree requise ? | OutputSchema |
66
+ | Type de contenu ? | Choix modele |
67
+ | Reponse structuree ? | OutputSchema |
194
68
  | Multi-langue ? | Variables langue |
195
- | Budget limite ? | ProviderInstance avec limit |
196
- | Temps reel requis ? | Streaming |
197
-
198
- ### ETAPE 2: Creer le Prompt
69
+ | Budget limite ? | ProviderInstance |
70
+ | Temps reel ? | Streaming |
199
71
 
72
+ ### 2. Creer le Prompt
200
73
  ```csharp
201
- // Via IPromptService
202
74
  var promptId = await _promptService.CreatePromptAsync(new CreatePromptRequest
203
75
  {
204
76
  Code = "ticket-analyzer",
205
77
  Name = "Ticket Analyzer",
206
- Description = "Analyse les tickets support pour categorisation",
207
- IsTemplate = false,
208
- Blocks = new[]
209
- {
210
- new CreateBlockRequest
211
- {
78
+ Blocks = new[] {
79
+ new CreateBlockRequest {
212
80
  BlockType = PromptBlockType.System,
213
- Label = "Instructions",
214
- Content = @"Tu es un expert en support technique.
215
- Analyse le ticket fourni et retourne:
216
- - Une categorie (technical, billing, general, urgent)
217
- - Un score de priorite (1-5)
218
- - Un resume en une phrase
219
- - Des tags pertinents
220
-
221
- Reponds UNIQUEMENT en JSON valide.",
222
- DisplayOrder = 1,
81
+ Content = "Instructions...",
223
82
  IsRequired = true
224
83
  },
225
- new CreateBlockRequest
226
- {
84
+ new CreateBlockRequest {
227
85
  BlockType = PromptBlockType.User,
228
- Label = "Ticket",
229
86
  Content = "Ticket: {{ticketTitle}}\nDescription: {{ticketDescription}}",
230
- DisplayOrder = 2,
231
87
  IsRequired = true
232
88
  }
233
89
  }
234
90
  });
235
91
  ```
236
92
 
237
- ### ETAPE 3: Definir le Schema de Validation
238
-
93
+ ### 3. Definir OutputSchema (si reponse structuree)
239
94
  ```csharp
240
- // JSON Schema pour validation automatique
241
95
  var schemaId = await _schemaService.CreateAsync(new CreateSchemaRequest
242
96
  {
243
97
  Code = "ticket-analysis-result",
244
- Name = "Ticket Analysis Result",
245
- JsonSchema = @"{
246
- ""$schema"": ""http://json-schema.org/draft-07/schema#"",
247
- ""type"": ""object"",
248
- ""required"": [""category"", ""priority"", ""summary"", ""tags""],
249
- ""properties"": {
250
- ""category"": {
251
- ""type"": ""string"",
252
- ""enum"": [""technical"", ""billing"", ""general"", ""urgent""]
253
- },
254
- ""priority"": {
255
- ""type"": ""integer"",
256
- ""minimum"": 1,
257
- ""maximum"": 5
258
- },
259
- ""summary"": {
260
- ""type"": ""string"",
261
- ""maxLength"": 200
262
- },
263
- ""tags"": {
264
- ""type"": ""array"",
265
- ""items"": { ""type"": ""string"" },
266
- ""maxItems"": 5
267
- }
268
- }
269
- }",
98
+ JsonSchema = @"{ ""type"": ""object"", ""required"": [""category"", ""priority""], ... }",
270
99
  DotNetType = "SmartStack.Application.AI.TicketAnalysisResult"
271
100
  });
272
-
273
- // Lier au prompt
274
- await _promptService.UpdatePromptAsync(promptId, new UpdatePromptRequest
275
- {
276
- OutputSchemaId = schemaId
277
- });
278
101
  ```
279
102
 
280
- ### ETAPE 4: Executer le Prompt
281
-
103
+ ### 4. Executer le Prompt
282
104
  ```csharp
283
- // Execution simple (retourne string)
284
- var result = await _aiCompletionService.ExecutePromptAsync(
285
- promptId,
286
- new Dictionary<string, object>
287
- {
288
- ["ticketTitle"] = ticket.Title,
289
- ["ticketDescription"] = ticket.Description
290
- });
291
-
292
- if (result.Success)
105
+ // Execution simple
106
+ var result = await _aiService.ExecutePromptAsync(promptId, new Dictionary<string, object>
293
107
  {
294
- var content = result.Content; // JSON string
295
- _logger.LogInformation(
296
- "AI completed in {Ms}ms, {Input}/{Output} tokens",
297
- result.ExecutionTimeMs,
298
- result.InputTokens,
299
- result.OutputTokens);
300
- }
108
+ ["ticketTitle"] = ticket.Title,
109
+ ["ticketDescription"] = ticket.Description
110
+ });
301
111
 
302
- // Execution avec validation typee
303
- var typedResult = await _aiCompletionService
304
- .ExecutePromptWithValidationAsync<TicketAnalysisResult>(
305
- promptId,
306
- new Dictionary<string, object>
307
- {
308
- ["ticketTitle"] = ticket.Title,
309
- ["ticketDescription"] = ticket.Description
310
- });
311
-
312
- if (typedResult.Success && typedResult.IsValid)
313
- {
314
- var analysis = typedResult.Data; // TicketAnalysisResult type
315
- ticket.SetCategory(analysis.Category);
316
- ticket.SetPriority(analysis.Priority);
317
- ticket.AddTags(analysis.Tags);
318
- }
319
- else if (!typedResult.IsValid)
320
- {
321
- _logger.LogWarning(
322
- "AI response validation failed: {Errors}",
323
- string.Join(", ", typedResult.ValidationErrors));
324
- }
112
+ // Avec validation typee
113
+ var typedResult = await _aiService.ExecutePromptWithValidationAsync<TicketAnalysisResult>(
114
+ promptId, variables);
115
+ if (typedResult.Success && typedResult.IsValid) { /* use typedResult.Data */ }
325
116
  ```
326
117
 
327
- ---
328
-
329
118
  ## SERVICES IA
330
119
 
331
120
  ### IAiCompletionService
332
-
333
121
  ```csharp
334
- public interface IAiCompletionService
335
- {
336
- // Execution basique
337
- Task<AiCompletionResult> CompleteAsync(
338
- AiCompletionRequest request,
339
- CancellationToken ct = default);
340
-
341
- // Execution par prompt ID
342
- Task<AiCompletionResult> ExecutePromptAsync(
343
- Guid promptId,
344
- Dictionary<string, object>? variables = null,
345
- Guid? providerId = null,
346
- Guid? modelId = null,
347
- CancellationToken ct = default);
348
-
349
- // Execution avec validation schema
350
- Task<AiValidatedCompletionResult<T>> ExecutePromptWithValidationAsync<T>(
351
- Guid promptId,
352
- Dictionary<string, object>? variables = null,
353
- Guid? providerId = null,
354
- Guid? modelId = null,
355
- CancellationToken ct = default);
356
-
357
- // Par code de prompt
358
- Task<AiValidatedCompletionResult<T>> ExecutePromptByCodeWithValidationAsync<T>(
359
- string promptCode,
360
- Dictionary<string, object>? variables = null,
361
- Guid? providerId = null,
362
- Guid? modelId = null,
363
- CancellationToken ct = default);
364
-
365
- // Provider systeme par defaut
366
- Task<Guid?> GetSystemProviderIdAsync(CancellationToken ct = default);
367
- }
122
+ Task<AiCompletionResult> CompleteAsync(AiCompletionRequest request, CancellationToken ct);
123
+ Task<AiCompletionResult> ExecutePromptAsync(Guid promptId, Dictionary<string, object>? variables, ...);
124
+ Task<AiValidatedCompletionResult<T>> ExecutePromptWithValidationAsync<T>(Guid promptId, ...);
125
+ Task<AiValidatedCompletionResult<T>> ExecutePromptByCodeWithValidationAsync<T>(string promptCode, ...);
368
126
  ```
369
127
 
370
128
  ### IPromptService
371
-
372
129
  ```csharp
373
- public interface IPromptService
374
- {
375
- // CRUD Prompts
376
- Task<List<PromptDto>> GetAllPromptsAsync(PromptStatus? status, bool? isTemplate);
377
- Task<PromptDto> GetPromptByIdAsync(Guid promptId);
378
- Task<PromptDto> GetPromptByCodeAsync(string code, string? version = null);
379
- Task<PromptDto> GetActivePromptByCodeAsync(string code);
380
-
381
- // Rendu
382
- Task<string> RenderPromptAsync(string code, Dictionary<string, object>? variables = null);
383
-
384
- // Lifecycle
385
- Task<Guid> CreatePromptAsync(CreatePromptRequest request);
386
- Task UpdatePromptAsync(Guid promptId, UpdatePromptRequest request);
387
- Task<Guid> DuplicatePromptAsync(Guid promptId, string newVersion);
388
- Task ActivatePromptAsync(Guid promptId);
389
- Task DeactivatePromptAsync(Guid promptId);
390
- Task DeprecatePromptAsync(Guid promptId);
391
- Task DeletePromptAsync(Guid promptId);
392
-
393
- // Blocks
394
- Task AddBlockToPromptAsync(Guid promptId, CreateBlockRequest request);
395
- Task UpdateBlockAsync(Guid blockId, UpdateBlockRequest request);
396
- Task RemoveBlockFromPromptAsync(Guid promptId, Guid blockId);
397
- Task ReorderBlocksAsync(Guid promptId, Guid[] orderedBlockIds);
398
- }
130
+ Task<PromptDto> GetPromptByCodeAsync(string code, string? version = null);
131
+ Task<string> RenderPromptAsync(string code, Dictionary<string, object>? variables);
132
+ Task<Guid> CreatePromptAsync(CreatePromptRequest request);
133
+ Task ActivatePromptAsync(Guid promptId);
134
+ // Block management: AddBlockToPromptAsync, UpdateBlockAsync, ReorderBlocksAsync
399
135
  ```
400
136
 
401
- ---
402
-
403
- ## TEMPLATES INTEGRATION
404
-
405
- ### Template Service avec IA
406
-
407
- ```csharp
408
- public class TicketAnalysisService : ITicketAnalysisService
409
- {
410
- private readonly IAiCompletionService _aiService;
411
- private readonly ITicketRepository _ticketRepository;
412
- private readonly ILogger<TicketAnalysisService> _logger;
413
-
414
- public TicketAnalysisService(
415
- IAiCompletionService aiService,
416
- ITicketRepository ticketRepository,
417
- ILogger<TicketAnalysisService> logger)
418
- {
419
- _aiService = aiService;
420
- _ticketRepository = ticketRepository;
421
- _logger = logger;
422
- }
423
-
424
- public async Task<TicketAnalysisResult?> AnalyzeTicketAsync(
425
- Guid ticketId,
426
- CancellationToken ct)
427
- {
428
- var ticket = await _ticketRepository.GetByIdAsync(ticketId, ct);
429
- if (ticket == null) return null;
430
-
431
- try
432
- {
433
- var result = await _aiService
434
- .ExecutePromptByCodeWithValidationAsync<TicketAnalysisResult>(
435
- "ticket-analyzer",
436
- new Dictionary<string, object>
437
- {
438
- ["ticketTitle"] = ticket.Title,
439
- ["ticketDescription"] = ticket.Description,
440
- ["ticketCategory"] = ticket.Category?.Name ?? "Unknown"
441
- },
442
- cancellationToken: ct);
443
-
444
- if (result.Success && result.IsValid)
445
- {
446
- _logger.LogInformation(
447
- "Ticket {TicketId} analyzed: category={Category}, priority={Priority}",
448
- ticketId, result.Data.Category, result.Data.Priority);
449
-
450
- return result.Data;
451
- }
452
-
453
- if (!result.Success)
454
- {
455
- _logger.LogError(
456
- "AI analysis failed for ticket {TicketId}: {Error}",
457
- ticketId, result.Error);
458
- }
459
- else if (!result.IsValid)
460
- {
461
- _logger.LogWarning(
462
- "AI response invalid for ticket {TicketId}: {Errors}",
463
- ticketId, string.Join(", ", result.ValidationErrors));
464
- }
465
-
466
- return null;
467
- }
468
- catch (Exception ex)
469
- {
470
- _logger.LogError(ex, "Exception analyzing ticket {TicketId}", ticketId);
471
- return null;
472
- }
473
- }
474
- }
475
- ```
476
-
477
- ### Template DTO Result
478
-
479
- ```csharp
480
- // Application/AI/TicketAnalysisResult.cs
481
- public class TicketAnalysisResult
482
- {
483
- [JsonPropertyName("category")]
484
- public string Category { get; set; } = string.Empty;
485
-
486
- [JsonPropertyName("priority")]
487
- public int Priority { get; set; }
488
-
489
- [JsonPropertyName("summary")]
490
- public string Summary { get; set; } = string.Empty;
491
-
492
- [JsonPropertyName("tags")]
493
- public List<string> Tags { get; set; } = new();
494
-
495
- [JsonPropertyName("confidence")]
496
- public double? Confidence { get; set; }
497
- }
498
- ```
499
-
500
- ### Template Controller
501
-
502
- ```csharp
503
- [ApiController]
504
- [Route("api/[controller]")]
505
- public class TicketAnalysisController : ControllerBase
506
- {
507
- private readonly ITicketAnalysisService _analysisService;
508
-
509
- [HttpPost("{ticketId}/analyze")]
510
- [RequirePermission(Permissions.Support.Tickets.Update)]
511
- public async Task<ActionResult<TicketAnalysisResult>> AnalyzeTicket(
512
- Guid ticketId,
513
- CancellationToken ct)
514
- {
515
- var result = await _analysisService.AnalyzeTicketAsync(ticketId, ct);
516
-
517
- if (result == null)
518
- return BadRequest(new { message = "Analysis failed" });
519
-
520
- return Ok(result);
521
- }
522
- }
523
- ```
524
-
525
- ---
526
-
527
137
  ## FRONTEND INTEGRATION
528
138
 
529
- ### API IA
530
-
139
+ ### API
531
140
  ```typescript
532
- // services/api/aiApi.ts
533
- export const aiApi = {
534
- // Prompts
535
- getPrompts: (status?: PromptStatus, isTemplate?: boolean) =>
536
- apiClient.get<PromptDto[]>('/admin/ai/prompts', { params: { status, isTemplate } }),
537
-
538
- getPromptById: (id: string) =>
539
- apiClient.get<PromptDto>(`/admin/ai/prompts/${id}`),
540
-
541
- createPrompt: (data: CreatePromptRequest) =>
542
- apiClient.post<{ id: string }>('/admin/ai/prompts', data),
543
-
544
- // Execution
545
- executePrompt: (promptId: string, variables: Record<string, unknown>) =>
546
- apiClient.post<AiCompletionResult>(`/admin/ai/prompts/${promptId}/execute`, { variables }),
547
-
548
- previewPrompt: (promptId: string, variables: Record<string, unknown>) =>
549
- apiClient.post<{ rendered: string }>(`/admin/ai/prompts/${promptId}/preview`, { variables }),
550
-
551
- // Providers
552
- getProviders: () =>
553
- apiClient.get<AiProviderDto[]>('/admin/ai/providers'),
554
-
555
- getModels: (providerId?: string) =>
556
- apiClient.get<AiModelDto[]>('/admin/ai/models', { params: { providerId } }),
557
-
558
- // Schemas
559
- getSchemas: () =>
560
- apiClient.get<OutputSchemaDto[]>('/admin/ai/schemas'),
561
-
562
- createSchema: (data: CreateSchemaRequest) =>
563
- apiClient.post<{ id: string }>('/admin/ai/schemas', data),
564
- };
141
+ aiApi.getPrompts(status?, isTemplate?)
142
+ aiApi.executePrompt(promptId, variables)
143
+ aiApi.previewPrompt(promptId, variables)
144
+ aiApi.getProviders() / aiApi.getModels(providerId?)
145
+ aiApi.getSchemas() / aiApi.createSchema(data)
565
146
  ```
566
147
 
567
148
  ### Hook useAiCompletion
568
-
569
149
  ```typescript
570
- // hooks/useAiCompletion.ts
571
- import { useState } from 'react';
572
- import { aiApi } from '@/services/api/aiApi';
573
-
574
- export function useAiCompletion<T = unknown>(promptCode: string) {
575
- const [loading, setLoading] = useState(false);
576
- const [error, setError] = useState<string | null>(null);
577
- const [result, setResult] = useState<T | null>(null);
578
-
579
- const execute = async (variables: Record<string, unknown>) => {
580
- setLoading(true);
581
- setError(null);
582
-
583
- try {
584
- const response = await aiApi.executePrompt(promptCode, variables);
585
-
586
- if (response.success && response.isValid) {
587
- setResult(response.data as T);
588
- return response.data as T;
589
- } else {
590
- setError(response.error || 'Validation failed');
591
- return null;
592
- }
593
- } catch (err) {
594
- setError(err instanceof Error ? err.message : 'Unknown error');
595
- return null;
596
- } finally {
597
- setLoading(false);
598
- }
599
- };
600
-
601
- return { execute, loading, error, result };
602
- }
150
+ const { execute, loading, error, result } = useAiCompletion<T>(promptCode);
151
+ const data = await execute(variables);
603
152
  ```
604
153
 
605
- ### Composant AI Assistant
606
-
154
+ ### Composant AiAssistantButton
607
155
  ```tsx
608
- // components/ai/AiAssistantButton.tsx
609
- import { Sparkles, Loader2 } from 'lucide-react';
610
- import { useAiCompletion } from '@/hooks/useAiCompletion';
611
-
612
- interface AiAssistantButtonProps {
613
- promptCode: string;
614
- variables: Record<string, unknown>;
615
- onResult: (result: unknown) => void;
616
- label?: string;
617
- }
618
-
619
- export function AiAssistantButton({
620
- promptCode,
621
- variables,
622
- onResult,
623
- label = 'Analyser avec IA'
624
- }: AiAssistantButtonProps) {
625
- const { execute, loading, error } = useAiCompletion(promptCode);
626
-
627
- const handleClick = async () => {
628
- const result = await execute(variables);
629
- if (result) {
630
- onResult(result);
631
- }
632
- };
633
-
634
- return (
635
- <div>
636
- <button
637
- onClick={handleClick}
638
- disabled={loading}
639
- className="inline-flex items-center gap-2 px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 disabled:opacity-50"
640
- >
641
- {loading ? (
642
- <Loader2 className="w-4 h-4 animate-spin" />
643
- ) : (
644
- <Sparkles className="w-4 h-4" />
645
- )}
646
- {label}
647
- </button>
648
- {error && (
649
- <p className="mt-2 text-sm text-red-500">{error}</p>
650
- )}
651
- </div>
652
- );
653
- }
156
+ <AiAssistantButton
157
+ promptCode="ticket-analyzer"
158
+ variables={{ ticketTitle, ticketDescription }}
159
+ onResult={(result) => handleAnalysis(result)}
160
+ label="Analyser avec IA"
161
+ />
654
162
  ```
655
163
 
656
- ---
657
-
658
164
  ## PATTERNS AVANCES
659
165
 
660
- ### Pattern: Streaming Response
661
-
166
+ ### Streaming Response
662
167
  ```typescript
663
- // Pour les reponses longues, utiliser le streaming
664
- async function streamCompletion(promptId: string, variables: Record<string, unknown>) {
665
- const response = await fetch(`/api/ai/prompts/${promptId}/stream`, {
666
- method: 'POST',
667
- headers: { 'Content-Type': 'application/json' },
668
- body: JSON.stringify({ variables })
669
- });
670
-
671
- const reader = response.body?.getReader();
672
- const decoder = new TextDecoder();
673
-
674
- while (true) {
675
- const { done, value } = await reader!.read();
676
- if (done) break;
677
-
678
- const chunk = decoder.decode(value);
679
- // Afficher progressivement
680
- appendToOutput(chunk);
681
- }
682
- }
168
+ const reader = response.body?.getReader();
169
+ while (true) { const { done, value } = await reader.read(); if (done) break; /* append chunk */ }
683
170
  ```
684
171
 
685
- ### Pattern: Fallback Provider
686
-
172
+ ### Fallback Provider
687
173
  ```csharp
688
- // Si le provider principal echoue, fallback sur un autre
689
- public async Task<AiCompletionResult> CompleteWithFallbackAsync(
690
- Guid promptId,
691
- Dictionary<string, object> variables)
692
- {
693
- var providers = await _providerService.GetActiveProvidersAsync();
694
-
695
- foreach (var provider in providers.OrderBy(p => p.Priority))
696
- {
697
- try
698
- {
699
- var result = await _aiService.ExecutePromptAsync(
700
- promptId, variables, providerId: provider.Id);
701
-
702
- if (result.Success)
703
- return result;
704
- }
705
- catch (Exception ex)
706
- {
707
- _logger.LogWarning(ex,
708
- "Provider {Provider} failed, trying next",
709
- provider.Name);
710
- }
711
- }
712
-
713
- return new AiCompletionResult { Success = false, Error = "All providers failed" };
174
+ foreach (var provider in providers.OrderBy(p => p.Priority)) {
175
+ var result = await _aiService.ExecutePromptAsync(promptId, variables, providerId: provider.Id);
176
+ if (result.Success) return result;
714
177
  }
715
178
  ```
716
179
 
717
- ---
718
-
719
- ## CHECKLIST INTEGRATION IA
180
+ ## CHECKLIST
720
181
 
721
182
  ```
722
- Use case defini (generation, analyse, classification)
723
- Prompt cree avec:
724
- Code unique
725
- Blocks structures (System, User, etc.)
726
- Variables documentees
727
- Version definie
728
- OutputSchema cree si reponse structuree
729
- □ Service cree avec injection IAiCompletionService
730
- □ Gestion erreurs implementee
731
- □ Logging des executions (tokens, temps, erreurs)
732
- □ Frontend:
733
- □ Hook ou composant pour l'execution
734
- □ Loading state
735
- □ Error handling
736
- □ Affichage resultat
737
- □ Tests:
738
- □ Prompt execute correctement
739
- □ Variables substituees
740
- □ Schema valide la reponse
741
- □ Fallback fonctionne
742
- □ Budget/Usage:
743
- □ ProviderInstance avec limite
744
- □ Tracking des tokens
183
+ Prompt cree (Code unique, Blocks, Variables, Version)
184
+ OutputSchema si reponse structuree
185
+ Service avec IAiCompletionService injecte
186
+ Gestion erreurs + Logging (tokens, temps)
187
+ Frontend: Hook/composant, Loading, Error handling
188
+ ProviderInstance avec limite budget
189
+ Tests: execution, variables, validation schema
745
190
  ```
746
191
 
747
- ---
748
-
749
192
  ## REGLES ABSOLUES
750
193
 
751
- 1. **TOUJOURS** utiliser IAiCompletionService (jamais appel API direct)
752
- 2. **TOUJOURS** definir un OutputSchema pour les reponses structurees
753
- 3. **TOUJOURS** gerer les erreurs (API down, quota depasse, validation)
754
- 4. **TOUJOURS** logger les executions avec tokens et duree
755
- 5. **TOUJOURS** specifier la version du prompt
756
- 6. **TOUJOURS** utiliser des variables pour le contenu dynamique
757
- 7. **JAMAIS** hardcoder les cles API
758
- 8. **JAMAIS** exposer les prompts systeme au frontend
759
- 9. **JAMAIS** ignorer les limites de tokens
760
- 10. **JAMAIS** faire confiance aux reponses sans validation
761
-
762
- ---
194
+ | DO | DON'T |
195
+ |----|-------|
196
+ | IAiCompletionService pour executions | Appels API directs |
197
+ | OutputSchema pour reponses structurees | Reponses non validees |
198
+ | Gestion erreurs (API down, quota) | Ignorer les limites tokens |
199
+ | Logger executions (tokens, duree) | Hardcoder cles API |
200
+ | Variables pour contenu dynamique | Exposer prompts systeme au frontend |
763
201
 
764
202
  ## FICHIERS CLES
765
203
 
766
204
  | Fichier | Role |
767
205
  |---------|------|
768
206
  | `Domain/AI/Prompts/Prompt.cs` | Entite prompt |
769
- | `Domain/AI/Prompts/PromptBlock.cs` | Blocks du prompt |
770
207
  | `Domain/AI/Schemas/OutputSchema.cs` | Schema validation |
771
- | `Domain/AI/AiProvider.cs` | Provider IA |
772
- | `Domain/AI/AiModel.cs` | Modele IA |
773
208
  | `Domain/AI/AiProviderInstance.cs` | Instance configuree |
774
209
  | `Application/Common/Interfaces/IAiCompletionService.cs` | Interface service |
775
- | `Application/Common/Interfaces/IPromptService.cs` | Interface prompts |
776
210
  | `Infrastructure/Services/AI/AiCompletionService.cs` | Implementation |
777
- | `Infrastructure/Services/AI/PromptService.cs` | Implementation prompts |
778
211
  | `web/src/services/api/aiApi.ts` | API frontend |