Share what an Agents SDK run produced
Runner.run comes back. result.final_output holds the report. You print it,
the terminal wraps four thousand lines, and the person who asked for the
analysis is on Slack asking whether it is done.
Two ways in
A function tool is the shortest path:
from agents import Agent, Runner, function_tool
import httpx, os
@function_tool
def publish_report(title: str, html: str) -> str:
"""Publish an HTML report and return its shareable URL."""
r = httpx.post(
"https://commareports.com/api/v1/reports",
headers={"Authorization": f"Bearer {os.environ['COMMA_API_TOKEN']}"},
json={"title": title, "html": html},
)
r.raise_for_status()
return r.json()["url"]
agent = Agent(
name="analyst",
instructions=(
"Do the analysis, render it as a self-contained HTML report, "
"publish it with publish_report, and return only the URL."
),
tools=[publish_report],
)
An MCP server is the better path if you also use Comma from an editor, because it is the same endpoint and the same token:
from agents.mcp import MCPServerStreamableHttp
async with MCPServerStreamableHttp(
params={
"url": "https://commareports.com/api/mcp",
"headers": {"Authorization": f"Bearer {os.environ['COMMA_API_TOKEN']}"},
},
) as comma:
agent = Agent(name="analyst", instructions=..., mcp_servers=[comma])
The tool list is discovered, so publishing, updating and reading comments all arrive without you writing wrappers for each. Setup shape is in MCP setup.
Make the URL part of the type
The SDK's structured outputs are the clean way to stop HTML from sloshing around your program:
class Analysis(BaseModel):
summary: str
report_url: str
agent = Agent(name="analyst", output_type=Analysis, tools=[publish_report])
Now final_output is a short object with an address in it. The document lives
at the URL, the program handles a string, and nothing downstream has to decide
what to do with four thousand lines of markup — the point of
context budgeting for AI reports.
Handoffs: publish at the end, not everywhere
In a triage → research → writer chain, only the writer should hold the publish tool. Giving it to all three invites the triage agent to publish an introduction, and you end up with three reports where you wanted one.
Worth knowing
- Guardrails run first. Anything that checks the output for policy should trip before the publish tool, not after.
- Sessions make revisions natural. Keep the report id in session state and update it on the next turn, so one conversation produces one evolving report.
reports:write, pluscomments:readfor the review loop — see scoped tokens for AI agents.- 5 MB per report body.
Try it
Free — unlimited reports, commenters and revisions.