OpenAI ha lanzado discretamente GPT-5.1-Codex en la plataforma para desarrolladores, y muchos ya lo consideran el mejor modelo de programación disponible hoy. A diferencia de las versiones anteriores de Codex, GPT-5.1-Codex está diseñado para ingeniería de software real, razonamiento prolongado y agentes que usan herramientas.
En este tutorial construiremos un agente analizador de issues de GitHub completo usando OpenAI Agents y GPT-5.1 Codex.
Nuestro agente podrá:
Obtener issues directamente de cualquier repositorio de GitHub
Entender, desglosar y clasificar el issue
Inspeccionar solo los archivos y directorios relevantes del repo
Opcionalmente buscar en documentación y en la web con la API de Firecrawl
Generar un plan de ingeniería detallado, paso a paso, para resolver el issue
Este agente se comporta como un ingeniero senior: investiga, lee, razona y planifica antes de escribir nada. Puedes consultar nuestra guía sobre GPT-5.1 para ver qué más hay de nuevo.
¿Qué es GPT-5.1-Codex?
GPT-5.1 Codex es una versión especializada de GPT-5.1, creada para tareas de programación de larga duración y con agentes, no solo para autocompletar fragmentos. Está pensada para ingeniería de software real y flujos de trabajo con agentes, lo que la convierte en el motor perfecto para nuestro flujo de trabajo de automatización de Issue a Plan.
A diferencia de los modelos generales, Codex entiende los repositorios como lo haría un ingeniero senior: lee los issues, razona sobre la arquitectura, identifica los directorios adecuados y solo inspecciona los archivos que importan de verdad. Esto hace que el agente sea más rápido, más inteligente y mucho más eficiente en costes.
Codex está optimizado para tareas de programación largas y agentic. Se integra de forma natural con herramientas de desarrollo como GitHub CLI y la API de Firecrawl, permitiendo a nuestro agente obtener issues, explorar estructuras de proyectos online, leer archivos concretos y recopilar documentación cuando haga falta. Sigue las instrucciones al detalle, produce análisis limpios y fiables, y adapta su esfuerzo de razonamiento para avanzar rápido en tareas simples y profundizar en las complejas.
Al combinar una gran comprensión del código con razonamiento consciente de herramientas, GPT-5.1 Codex permite que nuestro agente convierta un issue de GitHub en un plan de ingeniería preciso y accionable, sin escanear todo el repo ni alucinar código. Es la columna vertebral del flujo de trabajo porque aporta la intuición, la estructura y la precisión de ingeniería de las que depende el proyecto.
Configuración del analizador de issues de GitHub
Antes de meternos en el proyecto, asegúrate de que tu entorno está listo. Necesitas tener Git instalado en tu máquina. Si no estás seguro, ejecuta git --version para confirmarlo. También necesitarás una cuenta de la OpenAI Developer Platform con al menos 6 $ de crédito para que las llamadas a la API no se interrumpan.
Después, crea una cuenta gratuita en Firecrawl y configura tus claves de API como variables de entorno. Son las que permiten que tu analizador se comunique con OpenAI y Firecrawl:
exportOPENAI_API_KEY=sk-...
exportFIRECRAWL_API_KEY="fc-..."Con la tecnología de
Cuando lo tengas, instala los paquetes de Python que impulsan el flujo. El primero, openai-agents, es un framework ligero que facilita muchísimo crear canalizaciones multiagente. El segundo, firecrawl-py, se encarga de rastrear y extraer información útil de tus repositorios o documentación.
Cómo crear un agente analizador de issues de GitHub con GPT-5.1-Codex
Crearemos una carpeta llamada "src" que contendrá todos los archivos de código. La carpeta "agents_pkg" guardará los archivos del agente y la carpeta "tools" contendrá los archivos de herramientas.
La aplicación principal, "app.py", ofrece una interfaz de línea de comandos (CLI) que utiliza los agentes de planificación para generar un informe de issue de GitHub a partir de la información que introduzcas.
Así debería verse el directorio de tu proyecto:
1. Herramientas web y de GitHub
Primero, crearemos un archivo de herramientas para agentes que ayudará al agente a acceder a GitHub y a la API de Firecrawl con funciones sencillas de Python.
Herramienta de la API de Firecrawl
Empezaremos por las herramientas. Crea un archivo llamado firecrawl_tools.py en el directorio src/tools y añade el siguiente código.
1. Crea y devuelve un cliente de Firecrawl usando FIRECRAWL_API_KEY de tu entorno, y lanzará un error si falta la clave.
import json
import os
from agents import function_tool
from firecrawl import firecrawl
def_get_firecrawl_client():
api_key = os.getenv("FIRECRAWL_API_KEY")ifnot api_key:raise RuntimeError("FIRECRAWL_API_KEY is not set")return firecrawl(api_key=api_key)Con la tecnología de
2. Usa Firecrawl para ejecutar una búsqueda web enfocada (p. ej., docs, posts, errores) y devuelve los resultados como JSON para que el agente los use como contexto externo.
@function_tooldeffirecrawl_search(query:str, limit:int=3)->str:"""
Run a Firecrawl search for docs related to the issue or tech stack.
Args:
query: Search query (usually based on issue title / framework / error message).
limit: Max number of results to return.
Returns:
JSON string of Firecrawl search results.
"""
client = _get_firecrawl_client()
results = client.search(query=query, limit=limit)return json.dumps(results)Con la tecnología de
3. Extrae una única URL con Firecrawl (en formato markdown) y devuelve el contenido estructurado de la página como JSON para una investigación técnica más profunda.
@function_tooldeffirecrawl_scrape(url:str)->str:"""
Scrape a single URL using Firecrawl for deeper research.
Args:
url: URL to scrape (docs, blog, README in another repo, etc.).
Returns:
JSON (markdown/structured) content from Firecrawl scrape.
"""
client = _get_firecrawl_client()
result = client.scrape(url=url, params={"formats":["markdown"]})return json.dumps(result)Con la tecnología de
Herramienta de GitHub CLI
Luego, crearemos un archivo llamado github_tools.py en el directorio src/tools y añadiremos el siguiente código.
1. Recupera un issue concreto de GitHub mediante GitHub CLI y devuelve sus detalles como JSON para que el agente los lea.
import base64
import json
import subprocess
from typing import List, Optional
from agents import function_tool
@function_tooldefget_github_issue(repo:str, issue_number:int)->str:"""
Fetch a GitHub issue using the GitHub CLI.
Args:
repo: Repository in 'owner/name' format.
issue_number: The issue number to fetch.
Returns:
A JSON string containing the issue fields (title, body, labels, URL, etc.),
or an error payload if the command fails.
"""try:
result = subprocess.run(["gh","issue","view",str(issue_number),"--repo",
repo,"--json","number,title,body,labels,url,author,createdAt,state,assignees",],
capture_output=True,
text=True,
check=True,)return result.stdout
except subprocess.CalledProcessError as e:return json.dumps({"error":"Failed to fetch issue via GitHub CLI","stderr": e.stderr,"repo": repo,"issue_number": issue_number,})Con la tecnología de
2. Lista solo los archivos relevantes en un repo remoto de GitHub (opcionalmente filtrados por ruta y extensión) para que el agente no escanee todo el proyecto.
@function_tooldeflist_repo_files_gh(
repo:str,
max_files:int=80,
extensions: Optional[List[str]]=None,
path_prefixes: Optional[List[str]]=None,)->str:"""
List *relevant* files in the remote repo using GitHub CLI.
Uses:
gh api repos/{repo}/git/trees/HEAD?recursive=1
The agent is expected to reason first which areas of the codebase are likely relevant
(e.g. 'src/', 'app/', 'backend/api/', 'cli/'), and then call this tool with a small
set of path_prefixes instead of scanning the entire project.
Args:
repo: Repository in 'owner/name' format (e.g. openai/openai-agents-python).
max_files: Max number of files to return.
extensions: Optional list of file extensions to keep (e.g. [".py", ".ts"]).
path_prefixes: Optional list of path prefixes to include (e.g. ["src/", "app/api/"]).
Returns:
JSON string with file paths and filters applied.
"""try:
result = subprocess.run(["gh","api",f"repos/{repo}/git/trees/HEAD?recursive=1",],
capture_output=True,
text=True,
check=True,)except subprocess.CalledProcessError as e:return json.dumps({"error":"Failed to list repo files via GitHub CLI","stderr": e.stderr,"repo": repo,})try:
data = json.loads(result.stdout)except json.JSONDecodeError:return json.dumps({"error":"Failed to parse JSON from gh api","raw": result.stdout[:2000],"repo": repo,})
tree = data.get("tree",[])if extensions isnotNoneandnotisinstance(extensions,list):
extensions =[str(extensions)]
exts =[e.lower()for e in(extensions or[])]if path_prefixes isnotNoneandnotisinstance(path_prefixes,list):
path_prefixes =[str(path_prefixes)]
prefixes =[p.strip()for p in(path_prefixes or[])if p.strip()]
paths: List[str]=[]for entry in tree:if entry.get("type")!="blob":continue# only files
path = entry.get("path","")ifnot path:continue# If prefixes are provided, only keep files under those subtreesif prefixes andnotany(path.startswith(pref)for pref in prefixes):continueif exts:
suffix ="."+ path.split(".")[-1].lower()if"."in path else""if suffix notin exts:continue
paths.append(path)iflen(paths)>= max_files:breakreturn json.dumps({"repo": repo,"count":len(paths),"files": paths,"filtered_by_extensions":bool(exts),"filtered_by_prefixes":bool(prefixes),})Con la tecnología de
3. Descarga y decodifica el contenido de un único archivo del repo usando GitHub CLI y devuelve el texto (recortado si es necesario) como JSON.
@function_tooldefget_repo_file_gh(
repo:str,
path:str,
ref:str="",
max_chars:int=8000,)->str:"""
Read a file's contents from the remote repo using GitHub CLI.
Uses:
gh api repos/{repo}/contents/{path} [ -F ref=<branch> ]
Args:
repo: Repository in 'owner/name' format.
path: File path in the repo (e.g. 'src/main.py').
ref: Optional branch / commit / tag ref (default: repo's default branch).
max_chars: Max characters of decoded content to return.
Returns:
JSON with file metadata and decoded content (truncated if needed),
or an error payload if anything fails.
"""
cmd =["gh","api",f"repos/{repo}/contents/{path}"]# Only add ref when explicitly set (GitHub default branch otherwise)if ref:
cmd +=["-F",f"ref={ref}"]try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
check=True,)except subprocess.CalledProcessError as e:return json.dumps({"error":"Failed to fetch file via GitHub CLI","stderr": e.stderr,"repo": repo,"path": path,"ref": ref or"DEFAULT_BRANCH",})try:
data = json.loads(result.stdout)except json.JSONDecodeError:return json.dumps({"error":"Failed to parse JSON from gh api (contents)","raw": result.stdout[:2000],"repo": repo,"path": path,})if data.get("type")!="file":return json.dumps({"error":"Path is not a file","repo": repo,"path": path,"data_type": data.get("type"),})
encoding = data.get("encoding")
content_b64 = data.get("content","")if encoding !="base64":return json.dumps({"error":"Unexpected encoding","repo": repo,"path": path,"encoding": encoding,})try:# GitHub often includes newlines in base64 payload
raw_bytes = base64.b64decode(content_b64)
text = raw_bytes.decode("utf-8", errors="replace")except Exception as e:# noqa: BLE001return json.dumps({"error":f"Failed to decode file content: {e}","repo": repo,"path": path,"encoding": encoding,})
truncated = text[:max_chars]return json.dumps({"repo": repo,"path": path,"ref": ref or"DEFAULT_BRANCH","truncated":len(text)> max_chars,"content": truncated,})Con la tecnología de
2. Agente de planificación
Aquí definimos un agente Issue Planner que sabe:
Leer un issue de GitHub
Decidir qué partes del código son relevantes
Inspeccionar solo un conjunto reducido de archivos mediante las herramientas de GitHub CLI
Llamar opcionalmente a Firecrawl para consultar documentación externa
Y finalmente devolver un plan de ejecución concreto, paso a paso.
Conectamos las herramientas de GitHub y Firecrawl, damos al agente instrucciones detalladas para trabajar con cabeza y control de costes, y le indicamos que use el modelo gpt-5.1-codex.
Crea el archivo planner_agent.py en el directorio src/agents_pkg y añade el siguiente código:
from agents import Agent
from tools.github_tools import(
get_github_issue,
list_repo_files_gh,
get_repo_file_gh,)from tools.firecrawl_tools import(
firecrawl_search,
firecrawl_scrape,)defbuild_planner_agent()-> Agent:"""
Issue Planner agent that:
- Reads the GitHub issue
- Reasons about which parts of the repo are relevant
- Uses GitHub CLI to inspect a *small* set of files online
- Uses Firecrawl for external research
- Outputs a concrete, step-by-step execution plan
"""return Agent(
name="Issue Planner",
instructions=("You are a senior software engineer.\n""Goal: Given a GitHub issue and the online repo (structure + files), plus optional ""external research, produce a clear, step-by-step execution plan to resolve the issue.\n\n""CONTEXT:\n""- All repository interaction must be done *online* via GitHub CLI tools.\n""- You have tools to: read the issue, list files under certain paths, read specific files, "" and call Firecrawl search/scrape for docs.\n\n""IMPORTANT STRATEGY (BE SMART):\n""- Be selective and cost-aware. Do NOT scan the whole project.\n""- First, deeply read the issue and infer which part of the system it affects:\n"" routing layer, CLI, API handlers, DB layer, tests, etc.\n""- Based on this reasoning, decide a small list of path prefixes and file types.\n\n""RECOMMENDED WORKFLOW:\n""1. Call get_github_issue(repo, issue_number) to fully understand the problem.\n""2. From the issue, infer a small list of path prefixes where relevant code likely lives,\n"" e.g. ['src/', 'app/', 'backend/api/', 'cli/'] depending on the project style.\n""3. Call list_repo_files_gh with:\n"" - extensions like ['.py', '.ts', '.js', '.tsx', '.jsx']\n"" - path_prefixes set to that small, targeted list\n"" This keeps the search focused instead of scanning the entire project.\n""4. From the returned file list, pick at most ~5-15 key files that are most likely related\n"" (entrypoints, routers, handlers, services, tests).\n""5. Call get_repo_file_gh(repo, path=...) only on those selected files to inspect the "" actual implementation.\n""6. If you need framework or library context (FastAPI, Click, React, etc.), use\n"" firecrawl_search and firecrawl_scrape to pull official docs or good examples.\n\n""OUTPUT FORMAT (execution plan):\n""After you have enough context from the issue + targeted code inspection (+ optional research), ""output a concise but concrete plan with sections:\n"" - Issue summary\n"" - Project/codebase understanding (where this issue lives in the architecture)\n"" - Key files / components to touch (with file paths)\n"" - Step-by-step implementation plan (Step 1, Step 2, ...)\n"" - Testing strategy (unit / integration / manual)\n"" - Edge cases, risks, and any open questions\n\n""The plan must be actionable for a mid-level developer. Avoid generic advice; tie your steps ""to the actual files and modules you inspected.\n"),
tools=[
get_github_issue,
list_repo_files_gh,
get_repo_file_gh,
firecrawl_search,
firecrawl_scrape,],
model="gpt-5.1-codex",)Con la tecnología de
3. App principal de CLI
Este es el archivo principal de Python que ofrece una interfaz de línea de comandos (CLI) e integra toda la lógica, callbacks y gestión de errores en un único archivo. Utiliza de forma eficiente las herramientas y agentes definidos en otros archivos.
1. Primero, configuramos e importamos todo lo necesario para la CLI. Incluimos librerías estándar, aseguramos salida Unicode en Windows para que se impriman correctamente emojis y símbolos, e importamos el runner de OpenAI junto con nuestro agente planificador.
2. Después, definimos las opciones de la línea de comandos, permitiéndote pasar un repositorio de GitHub y un número de issue al ejecutar la herramienta.
src/app.py:
import argparse
import asyncio
import json
import os
import pathlib
import sys
from datetime import datetime
# Set UTF-8 encoding for stdout to handle Unicode charactersif sys.platform =="win32":import codecs
sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())
sys.stderr = codecs.getwriter("utf-8")(sys.stderr.detach())from agents import Runner, ItemHelpers
from openai.types.responses import ResponseTextDeltaEvent
from agents_pkg.planner_agent import build_planner_agent
defparse_args()-> argparse.Namespace:
parser = argparse.ArgumentParser(
description=("Issue Planner: GPT-5.1-Codex + OpenAI Agents + GitHub CLI + Firecrawl\n"))
parser.add_argument("--repo",help="GitHub repo in 'owner/name' format (e.g. openai/openai-agents-python).",)
parser.add_argument("--issue",type=int,help="Issue number to plan for.",)return parser.parse_args()Con la tecnología de
3. Luego, recopilamos los inputs y preparamos el contexto. Leemos el repo y el issue de los argumentos, nos aseguramos de que la clave de la API de OpenAI está configurada, construimos un prompt claro que indica al agente cómo analizar el issue paso a paso y creamos un archivo markdown con sello temporal donde se guardará el plan final.
defget_user_input(args: argparse.Namespace)->tuple[str,int]:"""Get repository and issue number from arguments or user input."""
repo = args.repo orinput("GitHub repo (owner/name): ").strip()
issue_number = args.issue orint(input("Issue number: ").strip())return repo, issue_number
defvalidate_environment()->None:"""Validate that required environment variables are set."""ifnot os.getenv("OPENAI_API_KEY"):raise RuntimeError("OPENAI_API_KEY is not set")defbuild_user_prompt(repo:str, issue_number:int)->str:"""Build the user prompt for the agent."""return(f"You are helping me plan how to implement GitHub issue #{issue_number} "f"in repo '{repo}'.\n\n""Be selective and cost-aware:\n""1. Use get_github_issue(repo, issue_number) to understand the problem.\n""2. Based on the issue text, first reason about which directories and components "" are likely relevant.\n""3. Call list_repo_files_gh(repo, extensions=['.py', '.ts', '.js', '.tsx', '.jsx'], "" path_prefixes=[<your inferred prefixes>]) to only explore those areas.\n""4. From those results, choose a small set of the most relevant files and call "" get_repo_file_gh(repo, path=...) on them.\n""5. Optionally, use firecrawl_search and firecrawl_scrape if you need external docs.\n""6. Finally, generate the execution plan in the structured format from your instructions.")defsetup_output_file(repo:str, issue_number:int)-> pathlib.Path:"""Create output directory and return the markdown file path."""
output_dir = pathlib.Path("output")
output_dir.mkdir(exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
markdown_file = output_dir /f"execution_plan_{repo.replace('/','_')}_issue_{issue_number}_{timestamp}.md"return markdown_fileCon la tecnología de
4. Ahora hacemos visible el razonamiento del agente. Intentamos extraer un fragmento claro de razonamiento de cada evento e imprimimos una línea corta de “💭 Razonando…”; así, en lugar de ver los internos en bruto, tienes una pista legible de en qué está pensando el modelo.
defextract_reasoning_text(event_item)->str|None:"""Extract reasoning text from a reasoning event item."""
reasoning_text =Noneifhasattr(event_item,'raw_item'):
raw = event_item.raw_item
# Try multiple attribute namesfor attr_name in['content','text','reasoning','message','delta']:ifhasattr(raw, attr_name):
val =getattr(raw, attr_name)if val andstr(val).strip()andstr(val)!='None':
reasoning_text =str(val)break# If still not found, try to access as dict-likeifnot reasoning_text:try:ifhasattr(raw,'__dict__'):for key, val in raw.__dict__.items():if val andstr(val).strip()andstr(val)!='None'and key in['content','text','reasoning','message','delta']:
reasoning_text =str(val)breakexcept:pass# Also try direct attributes on event.itemifnot reasoning_text:for attr_name in['content','text','reasoning','message']:ifhasattr(event_item, attr_name):
val =getattr(event_item, attr_name)if val andstr(val).strip()andstr(val)!='None':
reasoning_text =str(val)breakreturn reasoning_text
defhandle_reasoning_event(event_item)->None:"""Handle and display reasoning events."""
reasoning_text = extract_reasoning_text(event_item)if reasoning_text and reasoning_text.strip():# Show first line or first 100 chars
first_line = reasoning_text.split('\n')[0].strip()[:100]iflen(reasoning_text.split('\n')[0].strip())>100:
first_line +="..."print(f"\n💭 Reasoning: {first_line}", flush=True)else:# Don't show "None" - just show that reasoning is happeningprint(f"\n💭 Reasoning...", flush=True)Con la tecnología de
5. Después, gestionamos las llamadas a herramientas y su seguimiento. Detectamos qué herramienta está usando el agente, formateamos sus argumentos (como repo, path o query) en una cadena compacta, imprimimos un mensaje “🔧 Llamando…” y mantenemos un mapa interno de herramientas activas para marcarlas como completadas y luego resumir todo lo que se ejecutó.
defextract_tool_info(event_item)->tuple[str|None,str|None]:"""Extract tool name and ID from a tool call event item."""
tool_name =None
tool_id =None# First try raw_item which contains the actual tool call dataifhasattr(event_item,'raw_item'):
raw = event_item.raw_item
# Try accessing tool_call through various paths
tool_call =Noneifhasattr(raw,'tool_call'):
tool_call = raw.tool_call
elifhasattr(raw,'function_call'):
tool_call = raw.function_call
if tool_call:# Try to get name from tool_callifhasattr(tool_call,'name'):
tool_name = tool_call.name
elifhasattr(tool_call,'function')andhasattr(tool_call.function,'name'):
tool_name = tool_call.function.name
# Try to get IDifhasattr(tool_call,'id'):
tool_id = tool_call.idelifhasattr(tool_call,'tool_call_id'):
tool_id = tool_call.tool_call_id
# Fallback: try direct attributes on rawifnot tool_name:ifhasattr(raw,'name'):
tool_name =getattr(raw,'name')elifhasattr(raw,'function')andhasattr(raw.function,'name'):
tool_name = raw.function.name
# Try using getattr with different possible attribute namesfor attr_name in['tool_name','function_name','name']:ifhasattr(raw, attr_name):
tool_name =getattr(raw, attr_name,None)if tool_name:break# Fallback to direct attributesifnot tool_name andhasattr(event_item,'tool_call'):
tool_call = event_item.tool_call
ifhasattr(tool_call,'name'):
tool_name = tool_call.name
ifhasattr(tool_call,'id'):
tool_id = tool_call.idelifhasattr(tool_call,'function')andhasattr(tool_call.function,'name'):
tool_name = tool_call.function.name
ifnot tool_name andhasattr(event_item,'name'):
tool_name = event_item.name
ifnot tool_name andhasattr(event_item,'function'):
func = event_item.function
ifhasattr(func,'name'):
tool_name = func.name
return tool_name, tool_id
defformat_tool_arguments(tool_call_obj)->str:"""Format tool arguments for display."""ifnot tool_call_obj ornothasattr(tool_call_obj,'arguments'):return""try:
args_dict = json.loads(tool_call_obj.arguments)ifisinstance(tool_call_obj.arguments,str)else tool_call_obj.arguments
if'repo'in args_dict:
tool_args =f" → {args_dict['repo']}"if'issue_number'in args_dict:
tool_args +=f"#{args_dict['issue_number']}"return tool_args
elif'path'in args_dict:returnf" → {args_dict['path']}"elif'query'in args_dict:
q =str(args_dict['query'])returnf" → {q[:40]}..."iflen(q)>40elsef" → {q}"elif'url'in args_dict:returnf" → {args_dict['url']}"elif'extensions'in args_dict or'path_prefixes'in args_dict:
parts =[]if'extensions'in args_dict:
parts.append(f"ext={args_dict['extensions']}")if'path_prefixes'in args_dict:
parts.append(f"paths={args_dict['path_prefixes']}")returnf" → {', '.join(parts)}"except:passreturn""defhandle_tool_call_event(event_item, active_tools:dict, tool_counter:int)->tuple[int,bool]:"""Handle tool call events and return updated tool_counter and whether event was handled."""
tool_name, tool_id = extract_tool_info(event_item)if tool_name:
tool_counter +=1
tool_id = tool_id orf"tool_{tool_counter}"
active_tools[tool_id]= tool_name
# Get tool arguments if available
tool_call_obj =Noneifhasattr(event_item,'raw_item')andhasattr(event_item.raw_item,'tool_call'):
tool_call_obj = event_item.raw_item.tool_call
elifhasattr(event_item,'tool_call'):
tool_call_obj = event_item.tool_call
tool_args = format_tool_arguments(tool_call_obj)print(f"\n[{tool_counter}] 🔧 Calling: {tool_name}{tool_args}...", flush=True)return tool_counter,Trueelse:# Still couldn't extract - try to inspect raw_item structureifhasattr(event_item,'raw_item'):
raw = event_item.raw_item
try:
raw_attrs =[attr for attr indir(raw)ifnot attr.startswith('_')]# Look for attributes that might contain the tool namefor attr in raw_attrs:try:
val =getattr(raw, attr)ifisinstance(val,str)and('get_github'in val.lower()or'list_repo'in val.lower()or'firecrawl'in val.lower()):
tool_name = val
break# Check if it's a dict-like object with nameifhasattr(val,'name'):
tool_name = val.name
breakexcept:continueif tool_name:
tool_counter +=1
tool_id = tool_id orf"tool_{tool_counter}"
active_tools[tool_id]= tool_name
print(f"\n[{tool_counter}] 🔧 Calling: {tool_name}...", flush=True)return tool_counter,Trueelse:# Print raw_item structure for debuggingprint(f"\n[DEBUG] raw_item attrs: {raw_attrs[:10]}", flush=True)except Exception as e:print(f"\n[DEBUG] Error inspecting raw_item: {e}", flush=True)return tool_counter,Falsedefhandle_tool_output_event(event_item, active_tools:dict, completed_tools:list)->None:"""Handle tool output events and track completed tools."""
tool_id =None# Try raw_item firstifhasattr(event_item,'raw_item')andhasattr(event_item.raw_item,'tool_call_id'):
tool_id = event_item.raw_item.tool_call_id
elifhasattr(event_item,'tool_call_id'):
tool_id = event_item.tool_call_id
elifhasattr(event_item,'raw_item')andhasattr(event_item.raw_item,'tool_call'):ifhasattr(event_item.raw_item.tool_call,'id'):
tool_id = event_item.raw_item.tool_call.idelifhasattr(event_item,'tool_call'):ifhasattr(event_item.tool_call,'id'):
tool_id = event_item.tool_call.idelifhasattr(event_item.tool_call,'function')andhasattr(event_item.tool_call.function,'name'):# Try to match by name if ID not available
tool_name_match = event_item.tool_call.function.name
for tid, tname in active_tools.items():if tname == tool_name_match:
tool_id = tid
breakif tool_id and tool_id in active_tools:
tool_name = active_tools.pop(tool_id)
completed_tools.append(tool_name)elif active_tools:# Fallback: use the first active tool
tool_id, tool_name =next(iter(active_tools.items()))
active_tools.pop(tool_id)
completed_tools.append(tool_name)Con la tecnología de
6. Ahora conectamos el bucle de streaming y la persistencia. Procesamos los eventos en streaming del agente, imprimimos los tokens según llegan, mostramos en tiempo real el razonamiento y las llamadas a herramientas, hacemos fallback con elegancia a una ejecución sin streaming si algo falla y, por último, escribimos el plan de ejecución completo en un archivo markdown con metadatos útiles.
asyncdefprocess_streaming_events(result, repo:str, issue_number:int)->str:"""Process streaming events from the agent execution."""
final_output =""
active_tools ={}# Track active tool calls by ID
tool_counter =0
completed_tools =[]
first_event_received =False# Stream the events as they come inasyncfor event in result.stream_events():# Handle raw response events (token-by-token streaming) - print immediatelyif event.type=="raw_response_event"andisinstance(event.data, ResponseTextDeltaEvent):ifnot first_event_received:
first_event_received =True
delta = event.data.delta
print(delta, end="", flush=True)
final_output += delta
# Handle run item events (higher level updates)elif event.type=="run_item_stream_event":
item_type =getattr(event.item,'type','unknown')# Show reasoning eventsif item_type =="reasoning_item":
handle_reasoning_event(event.item)elif item_type =="tool_call_item":
tool_counter, handled = handle_tool_call_event(event.item, active_tools, tool_counter)if handled:
first_event_received =Trueelif item_type =="tool_call_output_item":
handle_tool_output_event(event.item, active_tools, completed_tools)elif item_type =="message_output_item":
message_text = ItemHelpers.text_message_output(event.item)if message_text and(not final_output or message_text notin final_output):print(f"\n{message_text}", flush=True)
final_output += message_text
print()# Add newline after streaming# Show summary of tools usedif completed_tools:print(f"---\n\n📊 Tools used ({len(completed_tools)}): {', '.join(completed_tools)}", flush=True)# If no streaming events occurred, fall back to final outputifnot final_output:
final_output = result.final_output
if final_output:print(final_output, flush=True)return final_output
asyncdefrun_agent_with_streaming(agent, user_prompt:str, repo:str, issue_number:int)->str:"""Run the agent with streaming support and fallback handling."""try:# Run agent with streaming (run_streamed is synchronous, returns immediately)
result = Runner.run_streamed(
agent,input=user_prompt,
context={"repo": repo,"issue_number": issue_number},)returnawait process_streaming_events(result, repo, issue_number)except Exception as e:print(f"⚠️ Error: {e}", flush=True)# Fallback to standard async run
result =await Runner.run(
agent,input=user_prompt,
context={"repo": repo,"issue_number": issue_number},)print(result.final_output, flush=True)return result.final_output
defsave_output_to_file(markdown_file: pathlib.Path, repo:str, issue_number:int, final_output:str)->None:"""Save the final output to a markdown file."""withopen(markdown_file,'w', encoding='utf-8')as f:
f.write(f"# GitHub Issue Analysis: {repo}#{issue_number}\n\n")
f.write(f"**Generated on:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
f.write(f"**Repository:** {repo}\n")
f.write(f"**Issue Number:** {issue_number}\n\n")
f.write("---\n\n")
f.write(final_output)print(f"---\n\n✅ Saved: {markdown_file}", flush=True)Con la tecnología de
7. Por último, unimos todo en el punto de entrada principal. Analizamos los argumentos, obtenemos el repo y el issue, validamos el entorno, construimos el agente y su prompt, ejecutamos el planificador con streaming (con fallback a ejecución síncrona si hace falta) y guardamos el resultado.
asyncdefmain()->None:"""Main entry point for the application."""
args = parse_args()
repo, issue_number = get_user_input(args)
validate_environment()
agent = build_planner_agent()
user_prompt = build_user_prompt(repo, issue_number)
markdown_file = setup_output_file(repo, issue_number)print(f"\n🔍 Analyzing {repo}#{issue_number}...\n")# Run the agent with streaming supporttry:
final_output =await run_agent_with_streaming(agent, user_prompt, repo, issue_number)except Exception as e:print(f"⚠️ Error: {e}", flush=True)# Final fallback to standard sync run
result = Runner.run_sync(
agent,input=user_prompt,
context={"repo": repo,"issue_number": issue_number},)print(result.final_output, flush=True)
final_output = result.final_output
# Save output to file
save_output_to_file(markdown_file, repo, issue_number, final_output)if __name__ =="__main__":
asyncio.run(main())Con la tecnología de
Nota: El código fuente, la configuración y la documentación están disponibles en el repositorio de GitHub: kingabzpro/Issue-Analyzer. Revísalo y úsalo como guía al replicar los resultados.
Prueba del analizador de issues de GitHub
Hay dos formas de usar nuestra app CLI: en modo interactivo, donde la app te pedirá uno a uno el nombre del repositorio y el número del issue, y en modo CLI, donde debes proporcionar toda la información al lanzar la app.
Para iniciar el modo interactivo, escribe el siguiente comando:
Una vez iniciado, se te pedirá el nombre del repositorio y el número del issue, y la app comenzará a usar herramientas y razonamiento para ayudarte.
En pocos segundos, recibirás un resumen del issue y propuestas para resolverlo. Este resumen incluye detalles sobre las herramientas usadas y la ubicación del archivo markdown donde se ha guardado la información.
Puedes abrir el archivo markdown para revisar un plan de issue detallado.
El modo CLI requiere incluir el nombre del repositorio y el número de issue directamente en el comando, como se muestra a continuación:
python src/app.py --repo kingabzpro/Travel-with-Kimi-K2 --issue1Con la tecnología de
Todo el proceso se transmite en streaming, por lo que verás qué herramientas usa el agente y si está razonando bien o no. También verás la respuesta final en streaming.
Mejoras futuras
La versión actual del analizador de issues de GitHub está pensada para entender issues y generar planes de ejecución precisos.
Sin embargo, el verdadero potencial de un flujo de trabajo con agentes está en automatizar todos los pasos posteriores a la creación del plan. Estas son algunas mejoras importantes que puedes implementar en el sistema:
1. Creación automática de ramas y PR
El objetivo es transformar un plan en un pull request funcional de forma automática. Esto agilizará el desarrollo, permitiendo un flujo mucho más eficiente.
Esta función incluirá la capacidad de crear una nueva rama directamente desde el agente, lo que facilitará la implementación de cambios. Además, el agente aplicará modificaciones de código basadas en el plan generado y ejecutará flujos de GitHub CLI como gh pr create y gh pr view.
Además, el sistema generará automáticamente descripciones de PR, changelogs y referencias a issues vinculados. También aplicará etiquetas de forma inteligente, clasificando como correcciones de errores, mejoras o refactors.
En conjunto, esta iniciativa convierte al agente en un sistema autónomo de automatización de Issue a Pull Request, mejorando notablemente la productividad y la consistencia del ciclo de desarrollo.
2. Análisis por lotes de issues y ejecución masiva de herramientas
Esta mejora potenciará el análisis de issues introduciendo capacidades por lotes. En lugar de centrarse en problemas individuales, los equipos podrán escanear múltiples issues a la vez, ya sea en paralelo o en cola, lo que facilita gestionar grandes volúmenes de manera eficaz.
Además, facilitará identificar issues duplicados o relacionados, mejorando la organización. Se podrán clasificar por criterios como complejidad, subsistema o impacto.
Para agilizar aún más, los equipos podrán ejecutar herramientas de GitHub o Firecrawl en modo por lotes, incrementando la eficiencia. En definitiva, esta mejora ofrece un único comando capaz de priorizar automáticamente decenas o cientos de issues de una vez.
3. Pruebas pre-PR, comprobaciones de seguridad y validación
Antes de crear un pull request (PR), es esencial que el agente valide a fondo los cambios propuestos en lugar de simplemente generarlos. Esta validación debe incluir varias funciones planificadas, como ejecutar tests unitarios mediante GitHub Actions o runners locales para asegurar que el código se comporta como se espera.
La validación de dependencias también es clave: comprobar imports, detectar módulos que falten y resolver incompatibilidades de versiones que puedan afectar al proyecto. Además, linting, formateo y comprobación de tipos son cruciales para mantener la calidad del código.
Hay que asegurar que las modificaciones no rompen los pipelines de build existentes y detectar cambios rompientes en APIs o regresiones. Siguiendo estos pasos, garantizamos que el PR llegue limpio, seguro y listo para producción.
Reflexiones finales sobre GPT-5.1 Codex
Crear agentes avanzados y de varios pasos con GPT-5.1 Codex y openai-agents es sorprendentemente sencillo. Básicamente, define tus propias herramientas y dale al modelo instrucciones claras sobre cuándo y cómo usarlas.
En este tutorial he usado GitHub CLI porque es rápido, intuitivo y fácil de integrar, pero podrías usar igual de bien el SDK de Python de GitHub, llamadas directas a la API o cualquier otra utilidad de CLI o Bash. La flexibilidad es la clave.
Puedes ampliar esta configuración tanto como quieras.
Por ejemplo, podrías crear:
Un agente planificador (que ya hemos construido)
Un agente de acción que aplique cambios de código basados en el plan
Un agente de pruebas que ejecute tests y valide si los cambios han roto algo
Un agente de PR que abra un pull request con un resumen claro
El objetivo de este tutorial era mostrar de lo que GPT-5.1 Codex es realmente capaz: gestiona llamadas a herramientas sin esfuerzo, entiende grandes bases de código, realiza razonamiento estructurado y puede ejecutar cadenas de automatización largas sin necesidad de interacción constante.
Soy un científico de datos certificado que disfruta creando aplicaciones de aprendizaje automático y escribiendo blogs sobre ciencia de datos. Actualmente me centro en la creación de contenidos, la edición y el trabajo con grandes modelos lingüísticos.
Alternativas de código abierto a GPT-4 que pueden ofrecer un rendimiento similar y requieren menos recursos informáticos para funcionar. Estos proyectos vienen con instrucciones, fuentes de código, pesos del modelo, conjuntos de datos e IU de chatbot.
Aprende a utilizar modelos de IA generativa para crear un editor de imágenes, un chatbot similar a ChatGPT con pocos recursos y una aplicación clasificadora de aprobación de préstamos y a automatizar interacciones PDF y un asistente de voz con GPT.
Este tutorial le presentará todo lo que necesita saber sobre GPT-4 Vision, desde cómo acceder a él hasta ejemplos prácticos del mundo real y sus limitaciones.
DeepSeek-Coder-V2 es un modelo de lenguaje de código de código abierto que rivaliza con el rendimiento de GPT-4, Gemini 1.5 Pro, Claude 3 Opus, Llama 3 70B o Codestral.
Esta guía te acompanya a través de los fundamentos de la API ChatGPT, demostrando su potencial en el procesamiento del lenguaje natural y la comunicación impulsada por la IA.
OpenAI ha lanzado discretamente GPT-5.1-Codex en la plataforma para desarrolladores, y muchos ya lo consideran el mejor modelo de programación disponible hoy. A diferencia de las versiones anteriores de Codex, GPT-5.1-Codex está diseñado para ingeniería de software real, razonamiento prolongado y agentes que usan herramientas.
En este tutorial construiremos un agente analizador de issues de GitHub completo usando OpenAI Agents y GPT-5.1 Codex.
Nuestro agente podrá:
Este agente se comporta como un ingeniero senior: investiga, lee, razona y planifica antes de escribir nada. Puedes consultar nuestra guía sobre GPT-5.1 para ver qué más hay de nuevo.
¿Qué es GPT-5.1-Codex?
GPT-5.1 Codex es una versión especializada de GPT-5.1, creada para tareas de programación de larga duración y con agentes, no solo para autocompletar fragmentos. Está pensada para ingeniería de software real y flujos de trabajo con agentes, lo que la convierte en el motor perfecto para nuestro flujo de trabajo de automatización de Issue a Plan.
A diferencia de los modelos generales, Codex entiende los repositorios como lo haría un ingeniero senior: lee los issues, razona sobre la arquitectura, identifica los directorios adecuados y solo inspecciona los archivos que importan de verdad. Esto hace que el agente sea más rápido, más inteligente y mucho más eficiente en costes.
Codex está optimizado para tareas de programación largas y agentic. Se integra de forma natural con herramientas de desarrollo como GitHub CLI y la API de Firecrawl, permitiendo a nuestro agente obtener issues, explorar estructuras de proyectos online, leer archivos concretos y recopilar documentación cuando haga falta. Sigue las instrucciones al detalle, produce análisis limpios y fiables, y adapta su esfuerzo de razonamiento para avanzar rápido en tareas simples y profundizar en las complejas.
Al combinar una gran comprensión del código con razonamiento consciente de herramientas, GPT-5.1 Codex permite que nuestro agente convierta un issue de GitHub en un plan de ingeniería preciso y accionable, sin escanear todo el repo ni alucinar código. Es la columna vertebral del flujo de trabajo porque aporta la intuición, la estructura y la precisión de ingeniería de las que depende el proyecto.
Configuración del analizador de issues de GitHub
Antes de meternos en el proyecto, asegúrate de que tu entorno está listo. Necesitas tener Git instalado en tu máquina. Si no estás seguro, ejecuta
git --versionpara confirmarlo. También necesitarás una cuenta de la OpenAI Developer Platform con al menos 6 $ de crédito para que las llamadas a la API no se interrumpan.Después, crea una cuenta gratuita en Firecrawl y configura tus claves de API como variables de entorno. Son las que permiten que tu analizador se comunique con OpenAI y Firecrawl:
Cuando lo tengas, instala los paquetes de Python que impulsan el flujo. El primero, openai-agents, es un framework ligero que facilita muchísimo crear canalizaciones multiagente. El segundo, firecrawl-py, se encarga de rastrear y extraer información útil de tus repositorios o documentación.
Por último, asegúrate de que GitHub CLI está instalado y configurado. El siguiente comando te ayudará a iniciar sesión en tu cuenta de GitHub.
Cómo crear un agente analizador de issues de GitHub con GPT-5.1-Codex
Crearemos una carpeta llamada "src" que contendrá todos los archivos de código. La carpeta "agents_pkg" guardará los archivos del agente y la carpeta "tools" contendrá los archivos de herramientas.
La aplicación principal, "app.py", ofrece una interfaz de línea de comandos (CLI) que utiliza los agentes de planificación para generar un informe de issue de GitHub a partir de la información que introduzcas.
Así debería verse el directorio de tu proyecto:
1. Herramientas web y de GitHub
Primero, crearemos un archivo de herramientas para agentes que ayudará al agente a acceder a GitHub y a la API de Firecrawl con funciones sencillas de Python.
Herramienta de la API de Firecrawl
Empezaremos por las herramientas. Crea un archivo llamado firecrawl_tools.py en el directorio src/tools y añade el siguiente código.
1. Crea y devuelve un cliente de Firecrawl usando
FIRECRAWL_API_KEYde tu entorno, y lanzará un error si falta la clave.2. Usa Firecrawl para ejecutar una búsqueda web enfocada (p. ej., docs, posts, errores) y devuelve los resultados como JSON para que el agente los use como contexto externo.
3. Extrae una única URL con Firecrawl (en formato markdown) y devuelve el contenido estructurado de la página como JSON para una investigación técnica más profunda.
Herramienta de GitHub CLI
Luego, crearemos un archivo llamado github_tools.py en el directorio src/tools y añadiremos el siguiente código.
1. Recupera un issue concreto de GitHub mediante GitHub CLI y devuelve sus detalles como JSON para que el agente los lea.
2. Lista solo los archivos relevantes en un repo remoto de GitHub (opcionalmente filtrados por ruta y extensión) para que el agente no escanee todo el proyecto.
3. Descarga y decodifica el contenido de un único archivo del repo usando GitHub CLI y devuelve el texto (recortado si es necesario) como JSON.
2. Agente de planificación
Aquí definimos un agente Issue Planner que sabe:
Conectamos las herramientas de GitHub y Firecrawl, damos al agente instrucciones detalladas para trabajar con cabeza y control de costes, y le indicamos que use el modelo
gpt-5.1-codex.Crea el archivo
planner_agent.pyen el directoriosrc/agents_pkgy añade el siguiente código:3. App principal de CLI
Este es el archivo principal de Python que ofrece una interfaz de línea de comandos (CLI) e integra toda la lógica, callbacks y gestión de errores en un único archivo. Utiliza de forma eficiente las herramientas y agentes definidos en otros archivos.
1. Primero, configuramos e importamos todo lo necesario para la CLI. Incluimos librerías estándar, aseguramos salida Unicode en Windows para que se impriman correctamente emojis y símbolos, e importamos el runner de OpenAI junto con nuestro agente planificador.
2. Después, definimos las opciones de la línea de comandos, permitiéndote pasar un repositorio de GitHub y un número de issue al ejecutar la herramienta.
src/app.py:
3. Luego, recopilamos los inputs y preparamos el contexto. Leemos el repo y el issue de los argumentos, nos aseguramos de que la clave de la API de OpenAI está configurada, construimos un prompt claro que indica al agente cómo analizar el issue paso a paso y creamos un archivo markdown con sello temporal donde se guardará el plan final.
4. Ahora hacemos visible el razonamiento del agente. Intentamos extraer un fragmento claro de razonamiento de cada evento e imprimimos una línea corta de “💭 Razonando…”; así, en lugar de ver los internos en bruto, tienes una pista legible de en qué está pensando el modelo.
5. Después, gestionamos las llamadas a herramientas y su seguimiento. Detectamos qué herramienta está usando el agente, formateamos sus argumentos (como repo, path o query) en una cadena compacta, imprimimos un mensaje “🔧 Llamando…” y mantenemos un mapa interno de herramientas activas para marcarlas como completadas y luego resumir todo lo que se ejecutó.
6. Ahora conectamos el bucle de streaming y la persistencia. Procesamos los eventos en streaming del agente, imprimimos los tokens según llegan, mostramos en tiempo real el razonamiento y las llamadas a herramientas, hacemos fallback con elegancia a una ejecución sin streaming si algo falla y, por último, escribimos el plan de ejecución completo en un archivo markdown con metadatos útiles.
7. Por último, unimos todo en el punto de entrada principal. Analizamos los argumentos, obtenemos el repo y el issue, validamos el entorno, construimos el agente y su prompt, ejecutamos el planificador con streaming (con fallback a ejecución síncrona si hace falta) y guardamos el resultado.
Nota: El código fuente, la configuración y la documentación están disponibles en el repositorio de GitHub: kingabzpro/Issue-Analyzer. Revísalo y úsalo como guía al replicar los resultados.
Prueba del analizador de issues de GitHub
Hay dos formas de usar nuestra app CLI: en modo interactivo, donde la app te pedirá uno a uno el nombre del repositorio y el número del issue, y en modo CLI, donde debes proporcionar toda la información al lanzar la app.
Para iniciar el modo interactivo, escribe el siguiente comando:
Una vez iniciado, se te pedirá el nombre del repositorio y el número del issue, y la app comenzará a usar herramientas y razonamiento para ayudarte.
En pocos segundos, recibirás un resumen del issue y propuestas para resolverlo. Este resumen incluye detalles sobre las herramientas usadas y la ubicación del archivo markdown donde se ha guardado la información.
Puedes abrir el archivo markdown para revisar un plan de issue detallado.
El modo CLI requiere incluir el nombre del repositorio y el número de issue directamente en el comando, como se muestra a continuación:
Todo el proceso se transmite en streaming, por lo que verás qué herramientas usa el agente y si está razonando bien o no. También verás la respuesta final en streaming.
Mejoras futuras
La versión actual del analizador de issues de GitHub está pensada para entender issues y generar planes de ejecución precisos.
Sin embargo, el verdadero potencial de un flujo de trabajo con agentes está en automatizar todos los pasos posteriores a la creación del plan. Estas son algunas mejoras importantes que puedes implementar en el sistema:
1. Creación automática de ramas y PR
El objetivo es transformar un plan en un pull request funcional de forma automática. Esto agilizará el desarrollo, permitiendo un flujo mucho más eficiente.
Esta función incluirá la capacidad de crear una nueva rama directamente desde el agente, lo que facilitará la implementación de cambios. Además, el agente aplicará modificaciones de código basadas en el plan generado y ejecutará flujos de GitHub CLI como gh pr create y gh pr view.
Además, el sistema generará automáticamente descripciones de PR, changelogs y referencias a issues vinculados. También aplicará etiquetas de forma inteligente, clasificando como correcciones de errores, mejoras o refactors.
En conjunto, esta iniciativa convierte al agente en un sistema autónomo de automatización de Issue a Pull Request, mejorando notablemente la productividad y la consistencia del ciclo de desarrollo.
2. Análisis por lotes de issues y ejecución masiva de herramientas
Esta mejora potenciará el análisis de issues introduciendo capacidades por lotes. En lugar de centrarse en problemas individuales, los equipos podrán escanear múltiples issues a la vez, ya sea en paralelo o en cola, lo que facilita gestionar grandes volúmenes de manera eficaz.
Además, facilitará identificar issues duplicados o relacionados, mejorando la organización. Se podrán clasificar por criterios como complejidad, subsistema o impacto.
Para agilizar aún más, los equipos podrán ejecutar herramientas de GitHub o Firecrawl en modo por lotes, incrementando la eficiencia. En definitiva, esta mejora ofrece un único comando capaz de priorizar automáticamente decenas o cientos de issues de una vez.
3. Pruebas pre-PR, comprobaciones de seguridad y validación
Antes de crear un pull request (PR), es esencial que el agente valide a fondo los cambios propuestos en lugar de simplemente generarlos. Esta validación debe incluir varias funciones planificadas, como ejecutar tests unitarios mediante GitHub Actions o runners locales para asegurar que el código se comporta como se espera.
La validación de dependencias también es clave: comprobar imports, detectar módulos que falten y resolver incompatibilidades de versiones que puedan afectar al proyecto. Además, linting, formateo y comprobación de tipos son cruciales para mantener la calidad del código.
Hay que asegurar que las modificaciones no rompen los pipelines de build existentes y detectar cambios rompientes en APIs o regresiones. Siguiendo estos pasos, garantizamos que el PR llegue limpio, seguro y listo para producción.
Reflexiones finales sobre GPT-5.1 Codex
Crear agentes avanzados y de varios pasos con GPT-5.1 Codex y openai-agents es sorprendentemente sencillo. Básicamente, define tus propias herramientas y dale al modelo instrucciones claras sobre cuándo y cómo usarlas.
En este tutorial he usado GitHub CLI porque es rápido, intuitivo y fácil de integrar, pero podrías usar igual de bien el SDK de Python de GitHub, llamadas directas a la API o cualquier otra utilidad de CLI o Bash. La flexibilidad es la clave.
Puedes ampliar esta configuración tanto como quieras.
Por ejemplo, podrías crear:
El objetivo de este tutorial era mostrar de lo que GPT-5.1 Codex es realmente capaz: gestiona llamadas a herramientas sin esfuerzo, entiende grandes bases de código, realiza razonamiento estructurado y puede ejecutar cadenas de automatización largas sin necesidad de interacción constante.
Si te interesa aprender más sobre cómo crear agentes de IA, te recomiendo nuestro curso de AI Agents con Google ADK y también nuestra lista de proyectos de agentes de IA para construir.