# Hook exécuté après l’utilisation d’un outil

Le hook onPostToolUse est appelé après qu’un outil s’est exécuté avec succès. Utilisez-le pour :

<!-- markdownlint-disable GHD046 GHD005 -->

<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->

* Transformer ou filtrer les résultats de l’outil
* Exécution de l’outil de journalisation pour l’audit
* Ajouter un contexte en fonction des résultats
* Supprimer les résultats de la conversation

> ```
>           **Variante d’échec** : `onPostToolUse` se déclenche uniquement pour les exécutions réussies des outils. Pour observer les appels d’outils **échoués**, enregistrez `onPostToolUseFailure` (`on_post_tool_use_failure` en Python, `OnPostToolUseFailure` en Go/.NET, `on_post_tool_use_failure` en Rust). Le gestionnaire reçoit `{ sessionId, toolName, toolArgs, error, timestamp, workingDirectory }` ( le `error` champ est une chaîne extraite du résultat d’échec de l’outil) et peut revenir `{ additionalContext: string }` pour injecter des conseils supplémentaires pour le modèle (par exemple, des indicateurs de nouvelle tentative). Consultez [l’AUTOTITLE](/copilot/how-tos/copilot-sdk/hooks/hooks-overview) pour obtenir la liste complète.
> ```

<a id="failure-variant"></a>

## Signature du hook

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

```typescript
type PostToolUseHandler = (
  input: PostToolUseHookInput,
  invocation: HookInvocation,
) => Promise<PostToolUseHookOutput | null | undefined>;
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

```python
PostToolUseHandler = Callable[
    [PostToolUseHookInput, dict[str, str]],
    Awaitable[PostToolUseHookOutput | None]
]
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

```golang
type PostToolUseHandler func(
    input PostToolUseHookInput,
    invocation HookInvocation,
) (*PostToolUseHookOutput, error)
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

```csharp
public delegate Task<PostToolUseHookOutput?> PostToolUseHandler(
    PostToolUseHookInput input,
    HookInvocation invocation);
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

```java
@FunctionalInterface
public interface PostToolUseHandler {
    CompletableFuture<PostToolUseHookOutput> handle(
        PostToolUseHookInput input,
        HookInvocation invocation);
}
```

</div>

</div>

## Input

| Champ              | Catégorie                                                | Description                        |
| ------------------ | -------------------------------------------------------- | ---------------------------------- |
| `timestamp`        | Type d’horodatage du Kit de développement logiciel (SDK) | Lorsque le crochet a été déclenché |
| `workingDirectory` | string                                                   | Répertoire de travail actuel       |
| `toolName`         | string                                                   | Nom de l’outil appelé              |
| `toolArgs`         | Objet                                                    | Arguments passés à l’outil         |
| `toolResult`       | Objet                                                    | Résultat retourné par l’outil      |

## Sortie

Retournez `null` ou `undefined` pour laisser le résultat inchangé. Sinon, retournez un objet avec l’un de ces champs :

| Champ               | Catégorie | Description                                                            |
| ------------------- | --------- | ---------------------------------------------------------------------- |
| `modifiedResult`    | Objet     | Résultat modifié à utiliser au lieu d’origine                          |
| `additionalContext` | string    | Contexte supplémentaire injecté dans la conversation                   |
| `suppressOutput`    | booléen   | Si la valeur est true, le résultat n’apparaît pas dans la conversation |

## Exemples

### Journaliser tous les résultats de l’outil

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

```typescript
const session = await client.createSession({
  hooks: {
    onPostToolUse: async (input, invocation) => {
      console.log(`[${invocation.sessionId}] Tool: ${input.toolName}`);
      console.log(`  Args: ${JSON.stringify(input.toolArgs)}`);
      console.log(`  Result: ${JSON.stringify(input.toolResult)}`);
      return null; // Pass through unchanged
    },
  },
});
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

```python
from copilot.session import PermissionHandler

async def on_post_tool_use(input_data, invocation):
    print(f"[{invocation['session_id']}] Tool: {input_data['toolName']}")
    print(f"  Args: {input_data['toolArgs']}")
    print(f"  Result: {input_data['toolResult']}")
    return None  # Pass through unchanged

session = await client.create_session(on_permission_request=PermissionHandler.approve_all, hooks={"on_post_tool_use": on_post_tool_use})
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

```golang
session, _ := client.CreateSession(context.Background(), &copilot.SessionConfig{
    Hooks: &copilot.SessionHooks{
        OnPostToolUse: func(input copilot.PostToolUseHookInput, inv copilot.HookInvocation) (*copilot.PostToolUseHookOutput, error) {
            fmt.Printf("[%s] Tool: %s\n", inv.SessionID, input.ToolName)
            fmt.Printf("  Args: %v\n", input.ToolArgs)
            fmt.Printf("  Result: %v\n", input.ToolResult)
            return nil, nil
        },
    },
})
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

```csharp
var session = await client.CreateSessionAsync(new SessionConfig
{
    Hooks = new SessionHooks
    {
        OnPostToolUse = (input, invocation) =>
        {
            Console.WriteLine($"[{invocation.SessionId}] Tool: {input.ToolName}");
            Console.WriteLine($"  Args: {input.ToolArgs}");
            Console.WriteLine($"  Result: {input.ToolResult}");
            return Task.FromResult<PostToolUseHookOutput?>(null);
        },
    },
});
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

<!-- docs-validate: skip -->

```java
import com.github.copilot.*;
import com.github.copilot.rpc.*;
import java.util.concurrent.CompletableFuture;

var hooks = new SessionHooks()
    .setOnPostToolUse((input, invocation) -> {
        System.out.println("[" + invocation.getSessionId() + "] Tool: " + input.getToolName());
        System.out.println("  Args: " + input.getToolArgs());
        System.out.println("  Result: " + input.getToolResult());
        return CompletableFuture.completedFuture(null);
    });

var session = client.createSession(
    new SessionConfig()
        .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
        .setHooks(hooks)
).get();
```

</div>

</div>

### Réactez les données sensibles

```typescript
const SENSITIVE_PATTERNS = [
  /api[_-]?key["\s:=]+["']?[\w-]+["']?/gi,
  /password["\s:=]+["']?[\w-]+["']?/gi,
  /secret["\s:=]+["']?[\w-]+["']?/gi,
];

const session = await client.createSession({
  hooks: {
    onPostToolUse: async (input) => {
      if (typeof input.toolResult === "string") {
        let redacted = input.toolResult;
        for (const pattern of SENSITIVE_PATTERNS) {
          redacted = redacted.replace(pattern, "[REDACTED]");
        }

        if (redacted !== input.toolResult) {
          return { modifiedResult: redacted };
        }
      }
      return null;
    },
  },
});
```

### Tronquer les résultats volumineux

```typescript
const MAX_RESULT_LENGTH = 10000;

const session = await client.createSession({
  hooks: {
    onPostToolUse: async (input) => {
      const resultStr = JSON.stringify(input.toolResult);

      if (resultStr.length > MAX_RESULT_LENGTH) {
        return {
          modifiedResult: {
            truncated: true,
            originalLength: resultStr.length,
            content: resultStr.substring(0, MAX_RESULT_LENGTH) + "...",
          },
          additionalContext: `Note: Result was truncated from ${resultStr.length} to ${MAX_RESULT_LENGTH} characters.`,
        };
      }
      return null;
    },
  },
});
```

### Ajouter un contexte en fonction des résultats

```typescript
const session = await client.createSession({
  hooks: {
    onPostToolUse: async (input) => {
      // If a file read returned an error, add helpful context
      if (input.toolName === "read_file" && input.toolResult?.error) {
        return {
          additionalContext:
            "Tip: If the file doesn't exist, consider creating it or checking the path.",
        };
      }

      // If shell command failed, add debugging hint
      if (input.toolName === "shell" && input.toolResult?.exitCode !== 0) {
        return {
          additionalContext:
            "The command failed. Check if required dependencies are installed.",
        };
      }

      return null;
    },
  },
});
```

### Filtrer les traces de pile d’erreurs

```typescript
const session = await client.createSession({
  hooks: {
    onPostToolUse: async (input) => {
      if (input.toolResult?.error && input.toolResult?.stack) {
        // Remove internal stack trace details
        return {
          modifiedResult: {
            error: input.toolResult.error,
            // Keep only first 3 lines of stack
            stack: input.toolResult.stack.split("\n").slice(0, 3).join("\n"),
          },
        };
      }
      return null;
    },
  },
});
```

### Piste d’audit pour la conformité

```typescript
interface AuditEntry {
  timestamp: Date;
  sessionId: string;
  toolName: string;
  args: unknown;
  result: unknown;
  success: boolean;
}

const auditLog: AuditEntry[] = [];

const session = await client.createSession({
  hooks: {
    onPostToolUse: async (input, invocation) => {
      auditLog.push({
        timestamp: input.timestamp,
        sessionId: invocation.sessionId,
        toolName: input.toolName,
        args: input.toolArgs,
        result: input.toolResult,
        success: !input.toolResult?.error,
      });

      // Optionally persist to database/file
      await saveAuditLog(auditLog);

      return null;
    },
  },
});
```

### Supprimer les résultats bruyants

```typescript
const NOISY_TOOLS = ["list_directory", "search_codebase"];

const session = await client.createSession({
  hooks: {
    onPostToolUse: async (input) => {
      if (NOISY_TOOLS.includes(input.toolName)) {
        // Summarize instead of showing full result
        const items = Array.isArray(input.toolResult)
          ? input.toolResult
          : input.toolResult?.items || [];

        return {
          modifiedResult: {
            summary: `Found ${items.length} items`,
            firstFew: items.slice(0, 5),
          },
        };
      }
      return null;
    },
  },
});
```

## Bonnes pratiques

1. **Retourne `null` quand aucune modification n’est nécessaire** : cela est plus efficace que de renvoyer un objet vide ou le même résultat.

2. **Soyez prudent avec la modification des résultats** : la modification des résultats peut affecter la façon dont le modèle interprète la sortie de l’outil. Modifiez uniquement si nécessaire.

3. **Utiliser `additionalContext` pour les indicateurs** : au lieu de modifier les résultats, ajoutez un contexte pour aider le modèle à les interpréter.

4. **Prenez en compte la confidentialité lors de la journalisation** : les résultats de l’outil peuvent contenir des données sensibles. Tronquer les résultats volumineux.

5. **Veillez à ce que les hooks restent rapides** : les hooks post-outil s’exécutent de manière synchrone. Le traitement lourd doit être effectué de manière asynchrone ou par lot.

## Voir aussi

* [Utiliser des crochets](/fr/copilot/how-tos/copilot-sdk/hooks)
* [Hook exécuté avant l’utilisation d’un outil](/fr/copilot/how-tos/copilot-sdk/hooks/pre-tool-use)
* [Hook de gestion des erreurs](/fr/copilot/how-tos/copilot-sdk/hooks/error-handling)