OpenAI Agents SDK

Run the OpenAI Agents SDK against sference: Responses API, tools, handoffs, guardrails, and background steps on the 24h window.

OpenAI Agents SDK

The OpenAI Agents SDK is built on the Responses API, which sference serves natively. Point the client at sference and agents, handoffs, and guardrails run on open models.

Install

pip install -U openai-agents

Point the SDK at sference

import os
from agents import set_default_openai_client, set_default_openai_api
from openai import AsyncOpenAI

client = AsyncOpenAI(
    base_url="https://api.sference.com/v1",
    api_key=os.environ["SFERENCE_API_KEY"],
)

set_default_openai_client(client)
set_default_openai_api("responses")

Model names are catalog ids:

from agents import Agent, Runner

agent = Agent(
    name="Assistant",
    model="zai-org/GLM-5.3",
    instructions="You are a concise assistant. Answer in one paragraph.",
)

result = await Runner.run(agent, "Explain prefix caching in one paragraph.")
print(result.final_output)

Tools

The SDK's function-tool decorator produces the OpenAI tool schema, which sference accepts unchanged:

from agents import function_tool

@function_tool
def search_docs(query: str) -> str:
    """Search the internal documentation."""
    return docs_index.search(query)

agent = Agent(
    name="Docs assistant",
    model="moonshotai/Kimi-K3",
    instructions="Answer using search_docs. Cite the document title.",
    tools=[search_docs],
)

result = await Runner.run(agent, "How do I rotate an API key?")

Structured output

Use output_type with a Pydantic model — the SDK maps it to a JSON schema on the Responses API:

from pydantic import BaseModel

class Triage(BaseModel):
    severity: str
    team: str
    summary: str

agent = Agent(
    name="Triage",
    model="zai-org/GLM-5.3",
    instructions="Classify the ticket.",
    output_type=Triage,
)

result = await Runner.run(agent, ticket_text)
triage: Triage = result.final_output

Handoffs

from agents import Agent, handoff

billing = Agent(name="Billing", model="zai-org/GLM-5.3-Flash", instructions="Handle billing questions.")
technical = Agent(name="Technical", model="zai-org/GLM-5.3", instructions="Handle technical questions.")

triage = Agent(
    name="Triage",
    model="zai-org/GLM-5.3-Flash",
    instructions="Route the user to the right specialist.",
    handoffs=[handoff(billing), handoff(technical)],
)

result = await Runner.run(triage, "My invoice is wrong.")

Use a cheap, fast model for the router and a stronger one for the specialist — the catalog spans GLM-5.3-Flash (0.20 / 0.60) to Kimi-K3 (3.00 / 15.00), so routing decisions are the natural place to economize.

Guardrails

from agents import Agent, GuardrailFunctionOutput, input_guardrail, Runner

@input_guardrail
async def no_pii(ctx, agent, input):
    flagged = contains_pii(str(input))
    return GuardrailFunctionOutput(output_info={"pii": flagged}, tripwire_triggered=flagged)

agent = Agent(
    name="Support",
    model="zai-org/GLM-5.3",
    instructions="Answer support questions.",
    input_guardrails=[no_pii],
)

Background steps on the 24h window

The SDK's Runner is synchronous from your code's perspective, but individual steps do not have to be. For long-horizon work — research passes, bulk classification, overnight evaluation — submit the step as a background response and collect it later:

response = await client.responses.create(
    model="zai-org/GLM-5.3",
    input=research_question,
    background=True,
    metadata={"completion_window": "24h"},
)
print(response.id)   # collect later, or register a webhook

Background responses bill at 0.5 × the list rate. For steps where someone is waiting but which are not on the critical path, service_tier: "flex" gives 0.7 ×. See Pricing.

`store` and conversation state

sference answers every request from the content you send — there is no server-side thread to point at. Pass the full conversation in input on each turn (the SDK does this by default) and do not rely on previous_response_id or a stored conversation. See API compatibility.

Tracing

The SDK's tracing exports to OpenAI's platform by default. To disable it or point it elsewhere:

from agents import set_tracing_disabled
set_tracing_disabled(True)

Cost control

client = AsyncOpenAI(
    base_url="https://api.sference.com/v1",
    api_key=os.environ["SFERENCE_API_KEY"],
    default_headers={"X-Sference-Run": run_id},   # your own correlation header
)
  • prompt_cache_key — set it to the run id so the system prompt and tool definitions bill at the cached rate on every step. See Prompt caching.
  • max_queue_wait_s — bound the wait and fail over. See Max queue wait.
  • Cheap routers, strong specialists — handoffs and guardrails rarely need the largest model.