{"meta":{"title":"Enlace de uso posterior a la herramienta","intro":"Se llama al enlace onPostToolUsedespués de que una herramienta ejecute correctamente. Úselo para:","product":"GitHub Copilot","breadcrumbs":[{"href":"/es/copilot","title":"GitHub Copilot"},{"href":"/es/copilot/how-tos","title":"Procedimientos"},{"href":"/es/copilot/how-tos/copilot-sdk","title":"SDK de Copilot"},{"href":"/es/copilot/how-tos/copilot-sdk/hooks","title":"Uso de enlaces"},{"href":"/es/copilot/how-tos/copilot-sdk/hooks/post-tool-use","title":"Uso de la herramienta de publicación"}],"documentType":"article"},"body":"# Enlace de uso posterior a la herramienta\n\nSe llama al enlace onPostToolUsedespués de que una herramienta ejecute correctamente. Úselo para:\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n* Resultados de la herramienta de transformación o filtro\n* Ejecución de la herramienta de registro para la auditoría\n* Agregar contexto basado en los resultados\n* Ocultar los resultados de la conversación\n\n> ```\n>           **Variante de fallo** — `onPostToolUse` solo se activa para ejecuciones correctas de herramientas. Para observar llamadas de herramientas **fallidas**, registre `onPostToolUseFailure` (`on_post_tool_use_failure` en Python, `OnPostToolUseFailure` en Go/.NET, `on_post_tool_use_failure` en Rust). El controlador recibe `{ sessionId, toolName, toolArgs, error, timestamp, workingDirectory }` ( el `error` campo es una cadena extraída del resultado del error de la herramienta) y puede volver `{ additionalContext: string }` a insertar instrucciones adicionales para el modelo (por ejemplo, sugerencias de reintento). Consulte [AUTOTITLE](/copilot/how-tos/copilot-sdk/hooks/hooks-overview) para obtener la lista completa.\n> ```\n\n<a id=\"failure-variant\"></a>\n\n## Firma de enlace\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\ntype PostToolUseHandler = (\n  input: PostToolUseHookInput,\n  invocation: HookInvocation,\n) => Promise<PostToolUseHookOutput | null | undefined>;\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\nPostToolUseHandler = Callable[\n    [PostToolUseHookInput, dict[str, str]],\n    Awaitable[PostToolUseHookOutput | None]\n]\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\ntype PostToolUseHandler func(\n    input PostToolUseHookInput,\n    invocation HookInvocation,\n) (*PostToolUseHookOutput, error)\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\npublic delegate Task<PostToolUseHookOutput?> PostToolUseHandler(\n    PostToolUseHookInput input,\n    HookInvocation invocation);\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n```java\n@FunctionalInterface\npublic interface PostToolUseHandler {\n    CompletableFuture<PostToolUseHookOutput> handle(\n        PostToolUseHookInput input,\n        HookInvocation invocation);\n}\n```\n\n</div>\n\n</div>\n\n## Entrada\n\n| Campo              | Tipo                            | Description                                |\n| ------------------ | ------------------------------- | ------------------------------------------ |\n| `timestamp`        | Tipo de marca de tiempo del SDK | Cuando se activó el enlace                 |\n| `workingDirectory` | string                          | Directorio de trabajo actual               |\n| `toolName`         | string                          | Nombre de la herramienta llamada           |\n| `toolArgs`         | object                          | Argumentos que se pasaron a la herramienta |\n| `toolResult`       | object                          | Resultado devuelto por la herramienta      |\n\n## Output\n\nDevuelve `null` o `undefined` para pasar el resultado sin cambios. De lo contrario, devuelve un objeto con cualquiera de estos campos:\n\n| Campo               | Tipo    | Description                                                    |\n| ------------------- | ------- | -------------------------------------------------------------- |\n| `modifiedResult`    | object  | Resultado modificado que se va a usar en lugar de original     |\n| `additionalContext` | string  | Contexto adicional insertado en la conversación                |\n| `suppressOutput`    | boolean | Si es verdadero, el resultado no aparecerá en la conversación. |\n\n## Ejemplos\n\n### Registrar todos los resultados de la herramienta\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\nconst session = await client.createSession({\n  hooks: {\n    onPostToolUse: async (input, invocation) => {\n      console.log(`[${invocation.sessionId}] Tool: ${input.toolName}`);\n      console.log(`  Args: ${JSON.stringify(input.toolArgs)}`);\n      console.log(`  Result: ${JSON.stringify(input.toolResult)}`);\n      return null; // Pass through unchanged\n    },\n  },\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\nfrom copilot.session import PermissionHandler\n\nasync def on_post_tool_use(input_data, invocation):\n    print(f\"[{invocation['session_id']}] Tool: {input_data['toolName']}\")\n    print(f\"  Args: {input_data['toolArgs']}\")\n    print(f\"  Result: {input_data['toolResult']}\")\n    return None  # Pass through unchanged\n\nsession = await client.create_session(on_permission_request=PermissionHandler.approve_all, hooks={\"on_post_tool_use\": on_post_tool_use})\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\nsession, _ := client.CreateSession(context.Background(), &copilot.SessionConfig{\n    Hooks: &copilot.SessionHooks{\n        OnPostToolUse: func(input copilot.PostToolUseHookInput, inv copilot.HookInvocation) (*copilot.PostToolUseHookOutput, error) {\n            fmt.Printf(\"[%s] Tool: %s\\n\", inv.SessionID, input.ToolName)\n            fmt.Printf(\"  Args: %v\\n\", input.ToolArgs)\n            fmt.Printf(\"  Result: %v\\n\", input.ToolResult)\n            return nil, nil\n        },\n    },\n})\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\nvar session = await client.CreateSessionAsync(new SessionConfig\n{\n    Hooks = new SessionHooks\n    {\n        OnPostToolUse = (input, invocation) =>\n        {\n            Console.WriteLine($\"[{invocation.SessionId}] Tool: {input.ToolName}\");\n            Console.WriteLine($\"  Args: {input.ToolArgs}\");\n            Console.WriteLine($\"  Result: {input.ToolResult}\");\n            return Task.FromResult<PostToolUseHookOutput?>(null);\n        },\n    },\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n<!-- docs-validate: skip -->\n\n```java\nimport com.github.copilot.*;\nimport com.github.copilot.rpc.*;\nimport java.util.concurrent.CompletableFuture;\n\nvar hooks = new SessionHooks()\n    .setOnPostToolUse((input, invocation) -> {\n        System.out.println(\"[\" + invocation.getSessionId() + \"] Tool: \" + input.getToolName());\n        System.out.println(\"  Args: \" + input.getToolArgs());\n        System.out.println(\"  Result: \" + input.getToolResult());\n        return CompletableFuture.completedFuture(null);\n    });\n\nvar session = client.createSession(\n    new SessionConfig()\n        .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)\n        .setHooks(hooks)\n).get();\n```\n\n</div>\n\n</div>\n\n### Redactar datos sensibles\n\n```typescript\nconst SENSITIVE_PATTERNS = [\n  /api[_-]?key[\"\\s:=]+[\"']?[\\w-]+[\"']?/gi,\n  /password[\"\\s:=]+[\"']?[\\w-]+[\"']?/gi,\n  /secret[\"\\s:=]+[\"']?[\\w-]+[\"']?/gi,\n];\n\nconst session = await client.createSession({\n  hooks: {\n    onPostToolUse: async (input) => {\n      if (typeof input.toolResult === \"string\") {\n        let redacted = input.toolResult;\n        for (const pattern of SENSITIVE_PATTERNS) {\n          redacted = redacted.replace(pattern, \"[REDACTED]\");\n        }\n\n        if (redacted !== input.toolResult) {\n          return { modifiedResult: redacted };\n        }\n      }\n      return null;\n    },\n  },\n});\n```\n\n### Truncar resultados grandes\n\n```typescript\nconst MAX_RESULT_LENGTH = 10000;\n\nconst session = await client.createSession({\n  hooks: {\n    onPostToolUse: async (input) => {\n      const resultStr = JSON.stringify(input.toolResult);\n\n      if (resultStr.length > MAX_RESULT_LENGTH) {\n        return {\n          modifiedResult: {\n            truncated: true,\n            originalLength: resultStr.length,\n            content: resultStr.substring(0, MAX_RESULT_LENGTH) + \"...\",\n          },\n          additionalContext: `Note: Result was truncated from ${resultStr.length} to ${MAX_RESULT_LENGTH} characters.`,\n        };\n      }\n      return null;\n    },\n  },\n});\n```\n\n### Agregar contexto basado en los resultados\n\n```typescript\nconst session = await client.createSession({\n  hooks: {\n    onPostToolUse: async (input) => {\n      // If a file read returned an error, add helpful context\n      if (input.toolName === \"read_file\" && input.toolResult?.error) {\n        return {\n          additionalContext:\n            \"Tip: If the file doesn't exist, consider creating it or checking the path.\",\n        };\n      }\n\n      // If shell command failed, add debugging hint\n      if (input.toolName === \"shell\" && input.toolResult?.exitCode !== 0) {\n        return {\n          additionalContext:\n            \"The command failed. Check if required dependencies are installed.\",\n        };\n      }\n\n      return null;\n    },\n  },\n});\n```\n\n### Filtrar seguimientos de pila de errores\n\n```typescript\nconst session = await client.createSession({\n  hooks: {\n    onPostToolUse: async (input) => {\n      if (input.toolResult?.error && input.toolResult?.stack) {\n        // Remove internal stack trace details\n        return {\n          modifiedResult: {\n            error: input.toolResult.error,\n            // Keep only first 3 lines of stack\n            stack: input.toolResult.stack.split(\"\\n\").slice(0, 3).join(\"\\n\"),\n          },\n        };\n      }\n      return null;\n    },\n  },\n});\n```\n\n### Seguimiento de auditoría para el cumplimiento\n\n```typescript\ninterface AuditEntry {\n  timestamp: Date;\n  sessionId: string;\n  toolName: string;\n  args: unknown;\n  result: unknown;\n  success: boolean;\n}\n\nconst auditLog: AuditEntry[] = [];\n\nconst session = await client.createSession({\n  hooks: {\n    onPostToolUse: async (input, invocation) => {\n      auditLog.push({\n        timestamp: input.timestamp,\n        sessionId: invocation.sessionId,\n        toolName: input.toolName,\n        args: input.toolArgs,\n        result: input.toolResult,\n        success: !input.toolResult?.error,\n      });\n\n      // Optionally persist to database/file\n      await saveAuditLog(auditLog);\n\n      return null;\n    },\n  },\n});\n```\n\n### Suprimir los resultados ruidosos\n\n```typescript\nconst NOISY_TOOLS = [\"list_directory\", \"search_codebase\"];\n\nconst session = await client.createSession({\n  hooks: {\n    onPostToolUse: async (input) => {\n      if (NOISY_TOOLS.includes(input.toolName)) {\n        // Summarize instead of showing full result\n        const items = Array.isArray(input.toolResult)\n          ? input.toolResult\n          : input.toolResult?.items || [];\n\n        return {\n          modifiedResult: {\n            summary: `Found ${items.length} items`,\n            firstFew: items.slice(0, 5),\n          },\n        };\n      }\n      return null;\n    },\n  },\n});\n```\n\n## procedimientos recomendados\n\n1. **Devolver `null` cuando no se necesitan cambios** : esto es más eficaz que devolver un objeto vacío o el mismo resultado.\n\n2. **Tenga cuidado con la modificación de resultados** : el cambio de los resultados puede afectar a la forma en que el modelo interpreta la salida de la herramienta. Modifique solo cuando sea necesario.\n\n3. **Usar `additionalContext` para sugerencias** : en lugar de modificar los resultados, agregue contexto para ayudar al modelo a interpretarlos.\n\n4. **Considere la privacidad al registrar** : los resultados de la herramienta pueden contener datos confidenciales. Aplique la redacción antes de registrar.\n\n5. **Mantener los enlaces rápidos**: los enlaces posteriores a la herramienta se ejecutan sincrónicamente. El procesamiento intensivo debe realizarse de forma asincrónica o por lotes.\n\n## Consulte también\n\n* [Uso de enlaces](/es/copilot/how-tos/copilot-sdk/hooks)\n* [Gancho previo al uso de la herramienta](/es/copilot/how-tos/copilot-sdk/hooks/pre-tool-use)\n* [Gancho de manejo de errores](/es/copilot/how-tos/copilot-sdk/hooks/error-handling)"}