chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
|
||||
from agents import Agent, Runner, gen_trace_id, trace
|
||||
|
||||
# This tool is still in experimental phase and the details could be changed until being GAed.
|
||||
from agents.extensions.experimental.codex import (
|
||||
CodexToolStreamEvent,
|
||||
CommandExecutionItem,
|
||||
ErrorItem,
|
||||
FileChangeItem,
|
||||
ItemCompletedEvent,
|
||||
ItemStartedEvent,
|
||||
ItemUpdatedEvent,
|
||||
McpToolCallItem,
|
||||
ReasoningItem,
|
||||
ThreadErrorEvent,
|
||||
ThreadOptions,
|
||||
ThreadStartedEvent,
|
||||
TodoListItem,
|
||||
TurnCompletedEvent,
|
||||
TurnFailedEvent,
|
||||
TurnOptions,
|
||||
TurnStartedEvent,
|
||||
WebSearchItem,
|
||||
codex_tool,
|
||||
)
|
||||
|
||||
|
||||
# This example runs the Codex CLI via the Codex tool wrapper.
|
||||
# You can configure the CLI path with CODEX_PATH or CodexOptions(codex_path_override="...").
|
||||
# codex_tool accepts options as keyword arguments or a plain dict.
|
||||
# For example: codex_tool(sandbox_mode="read-only") or codex_tool({"sandbox_mode": "read-only"}).
|
||||
async def on_codex_stream(payload: CodexToolStreamEvent) -> None:
|
||||
event = payload.event
|
||||
|
||||
if isinstance(event, ThreadStartedEvent):
|
||||
log(f"codex thread started: {event.thread_id}")
|
||||
return
|
||||
if isinstance(event, TurnStartedEvent):
|
||||
log("codex turn started")
|
||||
return
|
||||
if isinstance(event, TurnCompletedEvent):
|
||||
usage = event.usage
|
||||
log(f"codex turn completed, usage: {usage}")
|
||||
return
|
||||
if isinstance(event, TurnFailedEvent):
|
||||
error = event.error.message
|
||||
log(f"codex turn failed: {error}")
|
||||
return
|
||||
if isinstance(event, ThreadErrorEvent):
|
||||
log(f"codex stream error: {event.message}")
|
||||
return
|
||||
|
||||
if not isinstance(event, ItemStartedEvent | ItemUpdatedEvent | ItemCompletedEvent):
|
||||
return
|
||||
|
||||
item = event.item
|
||||
|
||||
if isinstance(item, ReasoningItem):
|
||||
text = item.text
|
||||
log(f"codex reasoning ({event.type}): {text}")
|
||||
return
|
||||
if isinstance(item, CommandExecutionItem):
|
||||
command = item.command
|
||||
output = item.aggregated_output
|
||||
output_preview = output[-200:] if isinstance(output, str) else ""
|
||||
status = item.status
|
||||
log(f"codex command {event.type}: {command} | status={status} | output={output_preview}")
|
||||
return
|
||||
if isinstance(item, McpToolCallItem):
|
||||
server = item.server
|
||||
tool = item.tool
|
||||
status = item.status
|
||||
log(f"codex mcp {event.type}: {server}.{tool} | status={status}")
|
||||
return
|
||||
if isinstance(item, FileChangeItem):
|
||||
changes = item.changes
|
||||
status = item.status
|
||||
log(f"codex file change {event.type}: {status} | {changes}")
|
||||
return
|
||||
if isinstance(item, WebSearchItem):
|
||||
log(f"codex web search {event.type}: {item.query}")
|
||||
return
|
||||
if isinstance(item, TodoListItem):
|
||||
items = item.items
|
||||
log(f"codex todo list {event.type}: {len(items)} items")
|
||||
return
|
||||
if isinstance(item, ErrorItem):
|
||||
log(f"codex error {event.type}: {item.message}")
|
||||
|
||||
|
||||
def _timestamp() -> str:
|
||||
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
|
||||
def log(message: str) -> None:
|
||||
timestamp = _timestamp()
|
||||
lines = str(message).splitlines() or [""]
|
||||
for line in lines:
|
||||
print(f"{timestamp} {line}")
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
agent = Agent(
|
||||
name="Codex Agent",
|
||||
instructions=(
|
||||
"Use the codex tool to inspect the workspace in read-only mode and answer the question. "
|
||||
"When skill names, which usually starts with `$`, are mentioned, "
|
||||
"you must rely on the codex tool to use the skill and answer the question.\n\n"
|
||||
"When you send the final answer, you must include the following info at the end:\n\n"
|
||||
"Run `codex resume <thread_id>` to continue the codex session."
|
||||
),
|
||||
tools=[
|
||||
# Run local Codex CLI as a sub process
|
||||
codex_tool(
|
||||
sandbox_mode="read-only",
|
||||
default_thread_options=ThreadOptions(
|
||||
# You can pass a Codex instance to customize CLI details
|
||||
# codex=Codex(executable_path="/path/to/codex", base_url="..."),
|
||||
model="gpt-5.5",
|
||||
model_reasoning_effort="low",
|
||||
network_access_enabled=True,
|
||||
web_search_enabled=False,
|
||||
approval_policy="never", # We'll update this example once the HITL is implemented
|
||||
),
|
||||
default_turn_options=TurnOptions(
|
||||
# Abort Codex CLI if no events arrive within this many seconds.
|
||||
idle_timeout_seconds=60,
|
||||
),
|
||||
on_stream=on_codex_stream,
|
||||
)
|
||||
],
|
||||
)
|
||||
trace_id = gen_trace_id()
|
||||
log(f"View trace: https://platform.openai.com/traces/trace?trace_id={trace_id}")
|
||||
|
||||
with trace("Codex tool example", trace_id=trace_id):
|
||||
log("Using the Codex tool to inspect pyproject.toml and summarize Python requirements...")
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
(
|
||||
"Inspect pyproject.toml in this repository and summarize the supported Python "
|
||||
"version plus the main local test command. Do not modify any files."
|
||||
),
|
||||
)
|
||||
log(result.final_output)
|
||||
|
||||
# Use local inspection in read-only mode.
|
||||
log(
|
||||
"Using the Codex tool to inspect AGENTS.md and summarize the local verification workflow..."
|
||||
)
|
||||
result = await Runner.run(
|
||||
agent,
|
||||
(
|
||||
"Inspect AGENTS.md and summarize the mandatory local verification commands for this "
|
||||
"repository. Do not modify any files or suggest code changes."
|
||||
),
|
||||
)
|
||||
log(result.final_output)
|
||||
# (A read-only summary of the local verification workflow will be displayed.)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user