Files
openai--openai-agents-python/examples/sandbox/tutorials/dataroom_qa/main.py
T
2026-07-13 12:39:17 +08:00

147 lines
4.5 KiB
Python

"""
Answer questions over a synthetic dataroom.
"""
import argparse
import asyncio
import sys
from pathlib import Path
from textwrap import dedent
from agents import Runner, RunResultStreaming, TResponseInputItem
from agents.run import RunConfig
from agents.sandbox import Manifest, SandboxAgent, SandboxRunConfig
from agents.sandbox.capabilities import Shell
from agents.sandbox.entries import File, LocalDir
if __package__ is None or __package__ == "":
sys.path.insert(0, str(Path(__file__).resolve().parents[4]))
from examples.sandbox.tutorials.misc import (
DEFAULT_SANDBOX_IMAGE,
create_sandbox_client_and_session,
load_env_defaults,
print_event,
run_interactive_loop,
)
DEMO_DIR = Path(__file__).resolve().parent
DATAROOM_DATA_DIR = DEMO_DIR.parent / "data" / "dataroom"
DEFAULT_QUESTION = (
"How did revenue, gross margin, operating income, and operating cash flow change in "
"FY2025 versus FY2024, and which segment contributed the most revenue?"
)
AGENTS_MD = dedent(
"""\
# AGENTS.md
Answer the user's financial question using only the synthetic 10-K packet in `data/`.
## Evidence & citations
- Cite every material claim with markdown links in these formats (no bare links):
- `[1](data/source-file.txt:line:14)` for text sources
- `[2](data/source-file.pdf:page:1)` for PDF sources (each synthetic PDF is one page)
- Use `rg` and `sed` to find and quote exact evidence; do not use `data/setup.py`.
Keep the final answer direct and finance-oriented.
"""
)
async def print_streamed_result(result: RunResultStreaming) -> list[TResponseInputItem]:
async for event in result.stream_events():
print_event(event)
print_event(str(result.final_output).strip())
return result.to_input_list()
async def main(
model: str, question: str, use_docker: bool, image: str, no_interactive: bool
) -> None:
if not (DATAROOM_DATA_DIR / "10-k-mdna-overview.txt").exists():
raise SystemExit(
"Run `uv run python examples/sandbox/tutorials/data/dataroom/setup.py` "
"before starting this demo."
)
manifest = Manifest(
entries={
"AGENTS.md": File(content=AGENTS_MD.encode("utf-8")),
"data": LocalDir(src=DATAROOM_DATA_DIR),
}
)
agent = SandboxAgent(
name="Dataroom Analyst",
model=model,
instructions=AGENTS_MD,
capabilities=[Shell()],
)
client, sandbox = await create_sandbox_client_and_session(
manifest=manifest,
use_docker=use_docker,
image=image,
)
try:
async with sandbox:
async def run_turn(
conversation: list[TResponseInputItem],
) -> list[TResponseInputItem]:
result = Runner.run_streamed(
agent,
conversation,
max_turns=20,
run_config=RunConfig(
sandbox=SandboxRunConfig(session=sandbox),
tracing_disabled=True,
workflow_name="Dataroom Q&A example",
),
)
return await print_streamed_result(result)
conversation: list[TResponseInputItem] = [{"role": "user", "content": question}]
conversation = await run_turn(conversation)
await run_interactive_loop(
conversation=conversation,
no_interactive=no_interactive,
run_turn=run_turn,
)
finally:
await client.delete(sandbox)
if __name__ == "__main__":
load_env_defaults(DEMO_DIR / ".env")
parser = argparse.ArgumentParser()
parser.add_argument(
"--model",
default="gpt-5.4-mini",
help="Model name to use.",
)
parser.add_argument(
"--question",
default=DEFAULT_QUESTION,
help="Prompt to send to the agent.",
)
parser.add_argument(
"--docker",
action="store_true",
help="Run this example in Docker instead of Unix-local.",
)
parser.add_argument(
"--image",
default=DEFAULT_SANDBOX_IMAGE,
help="Docker image to use when --docker is set.",
)
parser.add_argument(
"--no-interactive",
action="store_true",
help="Run the scripted turn and skip follow-up terminal input.",
)
args = parser.parse_args()
asyncio.run(main(args.model, args.question, args.docker, args.image, args.no_interactive))