@atlashub/smartstack-cli 1.5.0 → 1.5.2

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 (159) hide show
  1. package/.documentation/agents.html +920 -916
  2. package/.documentation/apex.html +1022 -1018
  3. package/.documentation/business-analyse.html +1505 -1501
  4. package/.documentation/commands.html +684 -680
  5. package/.documentation/css/styles.css +2168 -2168
  6. package/.documentation/efcore.html +2509 -2505
  7. package/.documentation/gitflow.html +2622 -2618
  8. package/.documentation/hooks.html +417 -413
  9. package/.documentation/index.html +327 -323
  10. package/.documentation/init.html +565 -0
  11. package/.documentation/installation.html +548 -462
  12. package/.documentation/js/app.js +794 -794
  13. package/.documentation/ralph-loop.html +534 -530
  14. package/.documentation/test-web.html +517 -513
  15. package/config/default-config.json +86 -86
  16. package/config/settings.json +53 -53
  17. package/config/settings.local.example.json +16 -16
  18. package/dist/index.js +18 -8
  19. package/dist/index.js.map +1 -1
  20. package/package.json +88 -88
  21. package/templates/agents/action.md +36 -36
  22. package/templates/agents/efcore/conflicts.md +84 -84
  23. package/templates/agents/efcore/db-deploy.md +51 -51
  24. package/templates/agents/efcore/db-reset.md +59 -59
  25. package/templates/agents/efcore/db-seed.md +56 -56
  26. package/templates/agents/efcore/db-status.md +64 -64
  27. package/templates/agents/efcore/migration.md +85 -85
  28. package/templates/agents/efcore/rebase-snapshot.md +62 -62
  29. package/templates/agents/efcore/scan.md +90 -90
  30. package/templates/agents/efcore/squash.md +67 -67
  31. package/templates/agents/explore-codebase.md +65 -65
  32. package/templates/agents/explore-docs.md +97 -97
  33. package/templates/agents/fix-grammar.md +49 -49
  34. package/templates/agents/gitflow/abort.md +45 -45
  35. package/templates/agents/gitflow/cleanup.md +85 -85
  36. package/templates/agents/gitflow/commit.md +40 -40
  37. package/templates/agents/gitflow/exec.md +48 -48
  38. package/templates/agents/gitflow/finish.md +92 -92
  39. package/templates/agents/gitflow/init.md +139 -139
  40. package/templates/agents/gitflow/merge.md +62 -62
  41. package/templates/agents/gitflow/plan.md +42 -42
  42. package/templates/agents/gitflow/pr.md +78 -78
  43. package/templates/agents/gitflow/review.md +49 -49
  44. package/templates/agents/gitflow/start.md +61 -61
  45. package/templates/agents/gitflow/status.md +32 -32
  46. package/templates/agents/snipper.md +36 -36
  47. package/templates/agents/websearch.md +46 -46
  48. package/templates/commands/_resources/formatting-guide.md +124 -124
  49. package/templates/commands/ai-prompt.md +315 -315
  50. package/templates/commands/apex/1-analyze.md +100 -100
  51. package/templates/commands/apex/2-plan.md +145 -145
  52. package/templates/commands/apex/3-execute.md +171 -171
  53. package/templates/commands/apex/4-examine.md +116 -116
  54. package/templates/commands/apex/5-tasks.md +209 -209
  55. package/templates/commands/apex.md +76 -76
  56. package/templates/commands/application/create.md +362 -362
  57. package/templates/commands/application/templates-backend.md +463 -463
  58. package/templates/commands/application/templates-frontend.md +517 -517
  59. package/templates/commands/application/templates-i18n.md +478 -478
  60. package/templates/commands/application/templates-seed.md +362 -362
  61. package/templates/commands/application.md +303 -303
  62. package/templates/commands/business-analyse/0-orchestrate.md +640 -640
  63. package/templates/commands/business-analyse/1-init.md +269 -269
  64. package/templates/commands/business-analyse/2-discover.md +520 -520
  65. package/templates/commands/business-analyse/3-analyse.md +408 -408
  66. package/templates/commands/business-analyse/4-specify.md +598 -598
  67. package/templates/commands/business-analyse/5-validate.md +326 -326
  68. package/templates/commands/business-analyse/6-handoff.md +746 -746
  69. package/templates/commands/business-analyse/7-doc-html.md +602 -602
  70. package/templates/commands/business-analyse/bug.md +325 -325
  71. package/templates/commands/business-analyse/change-request.md +368 -368
  72. package/templates/commands/business-analyse/hotfix.md +200 -200
  73. package/templates/commands/business-analyse.md +640 -640
  74. package/templates/commands/controller/create.md +216 -216
  75. package/templates/commands/controller/postman-templates.md +528 -528
  76. package/templates/commands/controller/templates.md +600 -600
  77. package/templates/commands/controller.md +337 -337
  78. package/templates/commands/create/agent.md +138 -138
  79. package/templates/commands/create/command.md +166 -166
  80. package/templates/commands/create/hook.md +234 -234
  81. package/templates/commands/create/plugin.md +329 -329
  82. package/templates/commands/create/project.md +507 -507
  83. package/templates/commands/create/skill.md +199 -199
  84. package/templates/commands/create.md +220 -220
  85. package/templates/commands/debug.md +95 -95
  86. package/templates/commands/documentation/module.md +202 -202
  87. package/templates/commands/documentation/templates.md +432 -432
  88. package/templates/commands/documentation.md +190 -190
  89. package/templates/commands/efcore/_env-check.md +153 -153
  90. package/templates/commands/efcore/conflicts.md +186 -186
  91. package/templates/commands/efcore/db-deploy.md +193 -193
  92. package/templates/commands/efcore/db-reset.md +426 -426
  93. package/templates/commands/efcore/db-seed.md +326 -326
  94. package/templates/commands/efcore/db-status.md +226 -226
  95. package/templates/commands/efcore/migration.md +400 -400
  96. package/templates/commands/efcore/rebase-snapshot.md +264 -264
  97. package/templates/commands/efcore/scan.md +198 -198
  98. package/templates/commands/efcore/squash.md +298 -298
  99. package/templates/commands/efcore.md +224 -224
  100. package/templates/commands/epct.md +69 -69
  101. package/templates/commands/explain.md +186 -186
  102. package/templates/commands/explore.md +45 -45
  103. package/templates/commands/feature-full.md +267 -267
  104. package/templates/commands/gitflow/1-init.md +1038 -1038
  105. package/templates/commands/gitflow/10-start.md +768 -768
  106. package/templates/commands/gitflow/11-finish.md +457 -457
  107. package/templates/commands/gitflow/12-cleanup.md +276 -276
  108. package/templates/commands/gitflow/13-sync.md +216 -216
  109. package/templates/commands/gitflow/14-rebase.md +251 -251
  110. package/templates/commands/gitflow/2-status.md +277 -277
  111. package/templates/commands/gitflow/3-commit.md +344 -344
  112. package/templates/commands/gitflow/4-plan.md +145 -145
  113. package/templates/commands/gitflow/5-exec.md +147 -147
  114. package/templates/commands/gitflow/6-abort.md +344 -344
  115. package/templates/commands/gitflow/7-pull-request.md +453 -355
  116. package/templates/commands/gitflow/8-review.md +240 -176
  117. package/templates/commands/gitflow/9-merge.md +451 -365
  118. package/templates/commands/gitflow.md +128 -128
  119. package/templates/commands/implement.md +663 -663
  120. package/templates/commands/init.md +567 -562
  121. package/templates/commands/mcp-integration.md +330 -330
  122. package/templates/commands/notification.md +129 -129
  123. package/templates/commands/oneshot.md +57 -57
  124. package/templates/commands/quick-search.md +72 -72
  125. package/templates/commands/ralph-loop/cancel-ralph.md +18 -18
  126. package/templates/commands/ralph-loop/help.md +126 -126
  127. package/templates/commands/ralph-loop/ralph-loop.md +18 -18
  128. package/templates/commands/review.md +106 -106
  129. package/templates/commands/utils/test-web-config.md +160 -160
  130. package/templates/commands/utils/test-web.md +151 -151
  131. package/templates/commands/validate.md +233 -233
  132. package/templates/commands/workflow.md +193 -193
  133. package/templates/gitflow/config.json +138 -138
  134. package/templates/hooks/ef-migration-check.md +139 -139
  135. package/templates/hooks/hooks.json +25 -25
  136. package/templates/hooks/stop-hook.sh +177 -177
  137. package/templates/skills/ai-prompt/SKILL.md +778 -778
  138. package/templates/skills/application/SKILL.md +563 -563
  139. package/templates/skills/application/templates-backend.md +450 -450
  140. package/templates/skills/application/templates-frontend.md +531 -531
  141. package/templates/skills/application/templates-i18n.md +520 -520
  142. package/templates/skills/application/templates-seed.md +647 -647
  143. package/templates/skills/business-analyse/SKILL.md +191 -191
  144. package/templates/skills/business-analyse/questionnaire.md +283 -283
  145. package/templates/skills/business-analyse/templates-frd.md +477 -477
  146. package/templates/skills/business-analyse/templates-react.md +580 -580
  147. package/templates/skills/controller/SKILL.md +240 -240
  148. package/templates/skills/controller/postman-templates.md +614 -614
  149. package/templates/skills/controller/templates.md +1468 -1468
  150. package/templates/skills/documentation/SKILL.md +133 -133
  151. package/templates/skills/documentation/templates.md +476 -476
  152. package/templates/skills/feature-full/SKILL.md +838 -838
  153. package/templates/skills/notification/SKILL.md +555 -555
  154. package/templates/skills/ui-components/SKILL.md +870 -870
  155. package/templates/skills/workflow/SKILL.md +582 -582
  156. package/templates/test-web/api-health.json +38 -38
  157. package/templates/test-web/minimal.json +19 -19
  158. package/templates/test-web/npm-package.json +46 -46
  159. package/templates/test-web/seo-check.json +54 -54
@@ -1,778 +1,778 @@
1
- ---
2
- name: ai-prompt
3
- description: |
4
- Integre les capacites IA dans les features SmartStack.
5
- Utiliser ce skill quand:
6
- - L'utilisateur veut integrer l'IA dans une fonctionnalite
7
- - L'utilisateur mentionne "prompt", "GPT", "Claude", "IA", "AI"
8
- - Creation d'un assistant ou chatbot
9
- - Generation de contenu automatique
10
- - Validation de reponses IA avec schema
11
- Types: Prompt, OutputSchema, Provider, Model
12
- ---
13
-
14
- # Skill AI Prompt SmartStack
15
-
16
- > **Architecture:** Prompt + Blocks → Provider + Model → Completion → Schema Validation
17
- > Multi-provider: OpenAI, Anthropic (Claude), Azure OpenAI, Google Gemini
18
-
19
- ## QUAND CE SKILL S'ACTIVE
20
-
21
- Claude invoque automatiquement ce skill quand il detecte :
22
-
23
- | Declencheur | Exemple |
24
- |-------------|---------|
25
- | Demande explicite | "Integre GPT pour generer des descriptions" |
26
- | Chatbot/Assistant | "Cree un assistant pour le support" |
27
- | Generation contenu | "Genere automatiquement des reponses" |
28
- | Analyse texte | "Analyse le sentiment des commentaires" |
29
- | Mots-cles | "prompt", "GPT", "Claude", "IA", "completion", "LLM" |
30
-
31
- ---
32
-
33
- ## ARCHITECTURE IA
34
-
35
- ```
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
- └────────────────────────────────────────────────────────────────────────────┘
88
- ```
89
-
90
- ---
91
-
92
- ## ENTITES PRINCIPALES
93
-
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
- ```
121
-
122
- ### AiProviderInstance
123
-
124
- ```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
172
- ```
173
-
174
- ### OutputSchema
175
-
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
189
-
190
- | Question | Impact |
191
- |----------|--------|
192
- | Quel type de contenu generer ? | Choix du modele |
193
- | Reponse structuree requise ? | OutputSchema |
194
- | Multi-langue ? | Variables langue |
195
- | Budget limite ? | ProviderInstance avec limit |
196
- | Temps reel requis ? | Streaming |
197
-
198
- ### ETAPE 2: Creer le Prompt
199
-
200
- ```csharp
201
- // Via IPromptService
202
- var promptId = await _promptService.CreatePromptAsync(new CreatePromptRequest
203
- {
204
- Code = "ticket-analyzer",
205
- Name = "Ticket Analyzer",
206
- Description = "Analyse les tickets support pour categorisation",
207
- IsTemplate = false,
208
- Blocks = new[]
209
- {
210
- new CreateBlockRequest
211
- {
212
- 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,
223
- IsRequired = true
224
- },
225
- new CreateBlockRequest
226
- {
227
- BlockType = PromptBlockType.User,
228
- Label = "Ticket",
229
- Content = "Ticket: {{ticketTitle}}\nDescription: {{ticketDescription}}",
230
- DisplayOrder = 2,
231
- IsRequired = true
232
- }
233
- }
234
- });
235
- ```
236
-
237
- ### ETAPE 3: Definir le Schema de Validation
238
-
239
- ```csharp
240
- // JSON Schema pour validation automatique
241
- var schemaId = await _schemaService.CreateAsync(new CreateSchemaRequest
242
- {
243
- 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
- }",
270
- DotNetType = "SmartStack.Application.AI.TicketAnalysisResult"
271
- });
272
-
273
- // Lier au prompt
274
- await _promptService.UpdatePromptAsync(promptId, new UpdatePromptRequest
275
- {
276
- OutputSchemaId = schemaId
277
- });
278
- ```
279
-
280
- ### ETAPE 4: Executer le Prompt
281
-
282
- ```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)
293
- {
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
- }
301
-
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
- }
325
- ```
326
-
327
- ---
328
-
329
- ## SERVICES IA
330
-
331
- ### IAiCompletionService
332
-
333
- ```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
- }
368
- ```
369
-
370
- ### IPromptService
371
-
372
- ```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
- }
399
- ```
400
-
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
- ## FRONTEND INTEGRATION
528
-
529
- ### API IA
530
-
531
- ```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
- };
565
- ```
566
-
567
- ### Hook useAiCompletion
568
-
569
- ```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
- }
603
- ```
604
-
605
- ### Composant AI Assistant
606
-
607
- ```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
- }
654
- ```
655
-
656
- ---
657
-
658
- ## PATTERNS AVANCES
659
-
660
- ### Pattern: Streaming Response
661
-
662
- ```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
- }
683
- ```
684
-
685
- ### Pattern: Fallback Provider
686
-
687
- ```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" };
714
- }
715
- ```
716
-
717
- ---
718
-
719
- ## CHECKLIST INTEGRATION IA
720
-
721
- ```
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
745
- ```
746
-
747
- ---
748
-
749
- ## REGLES ABSOLUES
750
-
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
- ---
763
-
764
- ## FICHIERS CLES
765
-
766
- | Fichier | Role |
767
- |---------|------|
768
- | `Domain/AI/Prompts/Prompt.cs` | Entite prompt |
769
- | `Domain/AI/Prompts/PromptBlock.cs` | Blocks du prompt |
770
- | `Domain/AI/Schemas/OutputSchema.cs` | Schema validation |
771
- | `Domain/AI/AiProvider.cs` | Provider IA |
772
- | `Domain/AI/AiModel.cs` | Modele IA |
773
- | `Domain/AI/AiProviderInstance.cs` | Instance configuree |
774
- | `Application/Common/Interfaces/IAiCompletionService.cs` | Interface service |
775
- | `Application/Common/Interfaces/IPromptService.cs` | Interface prompts |
776
- | `Infrastructure/Services/AI/AiCompletionService.cs` | Implementation |
777
- | `Infrastructure/Services/AI/PromptService.cs` | Implementation prompts |
778
- | `web/src/services/api/aiApi.ts` | API frontend |
1
+ ---
2
+ name: ai-prompt
3
+ description: |
4
+ Integre les capacites IA dans les features SmartStack.
5
+ Utiliser ce skill quand:
6
+ - L'utilisateur veut integrer l'IA dans une fonctionnalite
7
+ - L'utilisateur mentionne "prompt", "GPT", "Claude", "IA", "AI"
8
+ - Creation d'un assistant ou chatbot
9
+ - Generation de contenu automatique
10
+ - Validation de reponses IA avec schema
11
+ Types: Prompt, OutputSchema, Provider, Model
12
+ ---
13
+
14
+ # Skill AI Prompt SmartStack
15
+
16
+ > **Architecture:** Prompt + Blocks → Provider + Model → Completion → Schema Validation
17
+ > Multi-provider: OpenAI, Anthropic (Claude), Azure OpenAI, Google Gemini
18
+
19
+ ## QUAND CE SKILL S'ACTIVE
20
+
21
+ Claude invoque automatiquement ce skill quand il detecte :
22
+
23
+ | Declencheur | Exemple |
24
+ |-------------|---------|
25
+ | Demande explicite | "Integre GPT pour generer des descriptions" |
26
+ | Chatbot/Assistant | "Cree un assistant pour le support" |
27
+ | Generation contenu | "Genere automatiquement des reponses" |
28
+ | Analyse texte | "Analyse le sentiment des commentaires" |
29
+ | Mots-cles | "prompt", "GPT", "Claude", "IA", "completion", "LLM" |
30
+
31
+ ---
32
+
33
+ ## ARCHITECTURE IA
34
+
35
+ ```
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
+ └────────────────────────────────────────────────────────────────────────────┘
88
+ ```
89
+
90
+ ---
91
+
92
+ ## ENTITES PRINCIPALES
93
+
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
+ ```
121
+
122
+ ### AiProviderInstance
123
+
124
+ ```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
172
+ ```
173
+
174
+ ### OutputSchema
175
+
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
189
+
190
+ | Question | Impact |
191
+ |----------|--------|
192
+ | Quel type de contenu generer ? | Choix du modele |
193
+ | Reponse structuree requise ? | OutputSchema |
194
+ | Multi-langue ? | Variables langue |
195
+ | Budget limite ? | ProviderInstance avec limit |
196
+ | Temps reel requis ? | Streaming |
197
+
198
+ ### ETAPE 2: Creer le Prompt
199
+
200
+ ```csharp
201
+ // Via IPromptService
202
+ var promptId = await _promptService.CreatePromptAsync(new CreatePromptRequest
203
+ {
204
+ Code = "ticket-analyzer",
205
+ Name = "Ticket Analyzer",
206
+ Description = "Analyse les tickets support pour categorisation",
207
+ IsTemplate = false,
208
+ Blocks = new[]
209
+ {
210
+ new CreateBlockRequest
211
+ {
212
+ 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,
223
+ IsRequired = true
224
+ },
225
+ new CreateBlockRequest
226
+ {
227
+ BlockType = PromptBlockType.User,
228
+ Label = "Ticket",
229
+ Content = "Ticket: {{ticketTitle}}\nDescription: {{ticketDescription}}",
230
+ DisplayOrder = 2,
231
+ IsRequired = true
232
+ }
233
+ }
234
+ });
235
+ ```
236
+
237
+ ### ETAPE 3: Definir le Schema de Validation
238
+
239
+ ```csharp
240
+ // JSON Schema pour validation automatique
241
+ var schemaId = await _schemaService.CreateAsync(new CreateSchemaRequest
242
+ {
243
+ 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
+ }",
270
+ DotNetType = "SmartStack.Application.AI.TicketAnalysisResult"
271
+ });
272
+
273
+ // Lier au prompt
274
+ await _promptService.UpdatePromptAsync(promptId, new UpdatePromptRequest
275
+ {
276
+ OutputSchemaId = schemaId
277
+ });
278
+ ```
279
+
280
+ ### ETAPE 4: Executer le Prompt
281
+
282
+ ```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)
293
+ {
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
+ }
301
+
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
+ }
325
+ ```
326
+
327
+ ---
328
+
329
+ ## SERVICES IA
330
+
331
+ ### IAiCompletionService
332
+
333
+ ```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
+ }
368
+ ```
369
+
370
+ ### IPromptService
371
+
372
+ ```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
+ }
399
+ ```
400
+
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
+ ## FRONTEND INTEGRATION
528
+
529
+ ### API IA
530
+
531
+ ```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
+ };
565
+ ```
566
+
567
+ ### Hook useAiCompletion
568
+
569
+ ```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
+ }
603
+ ```
604
+
605
+ ### Composant AI Assistant
606
+
607
+ ```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
+ }
654
+ ```
655
+
656
+ ---
657
+
658
+ ## PATTERNS AVANCES
659
+
660
+ ### Pattern: Streaming Response
661
+
662
+ ```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
+ }
683
+ ```
684
+
685
+ ### Pattern: Fallback Provider
686
+
687
+ ```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" };
714
+ }
715
+ ```
716
+
717
+ ---
718
+
719
+ ## CHECKLIST INTEGRATION IA
720
+
721
+ ```
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
745
+ ```
746
+
747
+ ---
748
+
749
+ ## REGLES ABSOLUES
750
+
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
+ ---
763
+
764
+ ## FICHIERS CLES
765
+
766
+ | Fichier | Role |
767
+ |---------|------|
768
+ | `Domain/AI/Prompts/Prompt.cs` | Entite prompt |
769
+ | `Domain/AI/Prompts/PromptBlock.cs` | Blocks du prompt |
770
+ | `Domain/AI/Schemas/OutputSchema.cs` | Schema validation |
771
+ | `Domain/AI/AiProvider.cs` | Provider IA |
772
+ | `Domain/AI/AiModel.cs` | Modele IA |
773
+ | `Domain/AI/AiProviderInstance.cs` | Instance configuree |
774
+ | `Application/Common/Interfaces/IAiCompletionService.cs` | Interface service |
775
+ | `Application/Common/Interfaces/IPromptService.cs` | Interface prompts |
776
+ | `Infrastructure/Services/AI/AiCompletionService.cs` | Implementation |
777
+ | `Infrastructure/Services/AI/PromptService.cs` | Implementation prompts |
778
+ | `web/src/services/api/aiApi.ts` | API frontend |