# /ai-prompt - Gestion Prompts IA SmartStack

> **Synergie Skill/Commande:**
> - **Skill** (`templates/skills/ai-prompt/`) → Invocation automatique par Claude
> - **Commande** (`/ai-prompt`) → Invocation manuelle par l'utilisateur

---

## ARGUMENTS

```
/ai-prompt <action> [options]
```

| Action | Description |
|--------|-------------|
| `create` | Creer un nouveau prompt avec blocks |
| `schema` | Creer un schema de validation |
| `integrate` | Integrer l'IA dans un service existant |
| `test` | Tester un prompt avec des variables |

---

## WORKFLOW

### /ai-prompt create

Cree un nouveau prompt avec ses blocks.

**Questions:**
1. Code du prompt ? (kebab-case)
2. Nom descriptif ?
3. Description ?
4. Type ? (Analyzer, Generator, Classifier, Assistant)
5. Blocks a creer ? (System, User, Examples)
6. Schema de validation ? (oui/non)

**Actions:**
1. Creer le prompt via API ou seed
2. Ajouter les blocks
3. Creer le schema si requis
4. Lier le schema au prompt

### /ai-prompt schema

Cree un schema de validation JSON.

**Questions:**
1. Code du schema ?
2. Nom ?
3. Proprietes requises ?
4. Type .NET associe ?

**Actions:**
1. Generer le JSON Schema
2. Creer le DTO C# correspondant
3. Ajouter dans la base de donnees

### /ai-prompt integrate

Integre l'execution IA dans un service existant.

**Questions:**
1. Quel service modifier ?
2. Quelle methode ajouter ? (Analyze, Generate, Classify)
3. Quel prompt utiliser ?
4. Retour type ?

**Actions:**
1. Injecter `IAiCompletionService`
2. Creer la methode d'execution
3. Ajouter la validation du resultat
4. Logger l'execution

### /ai-prompt test

Teste un prompt avec des variables.

**Questions:**
1. Quel prompt tester ?
2. Variables a injecter ?

**Actions:**
1. Afficher le prompt rendu
2. Executer contre le provider
3. Afficher le resultat et les metriques

---

## TEMPLATES

### Template Prompt Block System

```csharp
new CreateBlockRequest
{
    BlockType = PromptBlockType.System,
    Label = "Instructions",
    Content = @"Tu es un expert en $DOMAIN.
Analyse le contenu fourni et retourne:
- $OUTPUT_1
- $OUTPUT_2
- $OUTPUT_3

Reponds UNIQUEMENT en JSON valide correspondant au schema fourni.",
    DisplayOrder = 1,
    IsRequired = true
}
```

### Template Prompt Block User

```csharp
new CreateBlockRequest
{
    BlockType = PromptBlockType.User,
    Label = "Input",
    Content = "Contenu: {{content}}\nContexte: {{context}}",
    DisplayOrder = 2,
    IsRequired = true
}
```

### Template JSON Schema

```json
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "required": ["$PROP_1", "$PROP_2"],
    "properties": {
        "$PROP_1": {
            "type": "string",
            "description": "$DESCRIPTION_1"
        },
        "$PROP_2": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10,
            "description": "$DESCRIPTION_2"
        },
        "$PROP_3": {
            "type": "array",
            "items": { "type": "string" },
            "maxItems": 5,
            "description": "$DESCRIPTION_3"
        }
    }
}
```

### Template DTO Result

```csharp
// Application/AI/{Entity}AnalysisResult.cs

public class {Entity}AnalysisResult
{
    [JsonPropertyName("$PROP_1")]
    public string $Prop1 { get; set; } = string.Empty;

    [JsonPropertyName("$PROP_2")]
    public int $Prop2 { get; set; }

    [JsonPropertyName("$PROP_3")]
    public List<string> $Prop3 { get; set; } = new();
}
```

### Template Service Integration

```csharp
public async Task<{Entity}AnalysisResult?> Analyze{Entity}Async(
    Guid entityId,
    CancellationToken ct)
{
    var entity = await _context.{Entity}s.FindAsync(entityId);
    if (entity == null) return null;

    try
    {
        var result = await _aiCompletionService
            .ExecutePromptByCodeWithValidationAsync<{Entity}AnalysisResult>(
                "{entity}-analyzer",
                new Dictionary<string, object>
                {
                    ["content"] = entity.Content,
                    ["context"] = entity.Context ?? ""
                },
                cancellationToken: ct);

        if (result.Success && result.IsValid)
        {
            _logger.LogInformation(
                "{Entity} {EntityId} analyzed in {Ms}ms: {Result}",
                entityId,
                result.ExecutionTimeMs,
                result.Data.$Prop1);

            return result.Data;
        }

        if (!result.Success)
        {
            _logger.LogError(
                "AI analysis failed for {Entity} {EntityId}: {Error}",
                entityId, result.Error);
        }
        else if (!result.IsValid)
        {
            _logger.LogWarning(
                "AI response invalid for {Entity} {EntityId}: {Errors}",
                entityId, string.Join(", ", result.ValidationErrors));
        }

        return null;
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Exception analyzing {Entity} {EntityId}", entityId);
        return null;
    }
}
```

### Template Controller Endpoint

```csharp
[HttpPost("{id}/analyze")]
[RequirePermission(Permissions.$Module.$Entity.Update)]
[ProducesResponseType(typeof({Entity}AnalysisResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<{Entity}AnalysisResult>> Analyze{Entity}(
    Guid id,
    CancellationToken ct)
{
    var result = await _service.Analyze{Entity}Async(id, ct);

    if (result == null)
        return BadRequest(new { message = "Analysis failed" });

    return Ok(result);
}
```

### Template Frontend Button

```tsx
import { Sparkles, Loader2 } from 'lucide-react';

interface AiAnalyzeButtonProps {
  entityId: string;
  onResult: (result: AnalysisResult) => void;
}

export function AiAnalyzeButton({ entityId, onResult }: AiAnalyzeButtonProps) {
  const [loading, setLoading] = useState(false);

  const handleAnalyze = async () => {
    setLoading(true);
    try {
      const result = await {module}Api.analyze(entityId);
      onResult(result);
      toast.success('Analyse terminee');
    } catch (error) {
      toast.error('Erreur lors de l\'analyse');
    } finally {
      setLoading(false);
    }
  };

  return (
    <button
      onClick={handleAnalyze}
      disabled={loading}
      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"
    >
      {loading ? (
        <Loader2 className="w-4 h-4 animate-spin" />
      ) : (
        <Sparkles className="w-4 h-4" />
      )}
      Analyser avec IA
    </button>
  );
}
```

---

## FICHIERS CLES

| Fichier | Role |
|---------|------|
| `Domain/AI/Prompts/Prompt.cs` | Entite prompt |
| `Domain/AI/Schemas/OutputSchema.cs` | Schema validation |
| `Application/Common/Interfaces/IAiCompletionService.cs` | Interface |
| `Infrastructure/Services/AI/AiCompletionService.cs` | Implementation |
| `Infrastructure/Services/AI/PromptService.cs` | Gestion prompts |

---

## REGLES

1. **TOUJOURS** creer un schema de validation pour les reponses structurees
2. **TOUJOURS** creer le DTO C# correspondant au schema
3. **TOUJOURS** logger les executions avec tokens et duree
4. **TOUJOURS** gerer les erreurs (API down, validation)
5. **JAMAIS** exposer les prompts systeme au frontend
6. **JAMAIS** hardcoder les cles API

---

User: $ARGUMENTS
