Skip to content

Commit 409fea8

Browse files
committed
Add Perplexity provider example via OpenAI-compatible Agent API
- examples/model_providers/perplexity_provider.py: routes Agent API calls to https://api.perplexity.ai using AsyncOpenAI + OpenAIChatCompletionsModel via a ModelProvider, with the default sonar-pro model. - examples/tools/perplexity_search.py: wraps Perplexity's Search API as a function tool using httpx. - examples/model_providers/README.md: documents the new Perplexity entry point. Both examples send the X-Pplx-Integration: openai-agents/<version> attribution header on every outgoing request. Signed-off-by: James Liounis <james.liounis@perplexity.ai>
1 parent 3a3f34f commit 409fea8

3 files changed

Lines changed: 201 additions & 0 deletions

File tree

examples/model_providers/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,17 @@ Direct-model examples let you override the target model:
2222
uv run examples/model_providers/any_llm_provider.py --model openrouter/openai/gpt-5.4-mini
2323
uv run examples/model_providers/litellm_provider.py --model openrouter/openai/gpt-5.4-mini
2424
```
25+
26+
## Perplexity
27+
28+
Perplexity exposes an OpenAI-compatible chat completions endpoint, so you can route
29+
requests through an `AsyncOpenAI` client by overriding `base_url`:
30+
31+
```bash
32+
export PERPLEXITY_API_KEY="..."
33+
uv run examples/model_providers/perplexity_provider.py
34+
```
35+
36+
See [`perplexity_provider.py`](perplexity_provider.py) for the full setup. A search-tool
37+
example using Perplexity's Search API is at
38+
[`examples/tools/perplexity_search.py`](../tools/perplexity_search.py).
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
from __future__ import annotations
2+
3+
import asyncio
4+
import importlib.metadata
5+
import os
6+
7+
from openai import AsyncOpenAI
8+
9+
from agents import (
10+
Agent,
11+
Model,
12+
ModelProvider,
13+
OpenAIChatCompletionsModel,
14+
RunConfig,
15+
Runner,
16+
function_tool,
17+
set_tracing_disabled,
18+
)
19+
20+
"""Use Perplexity's Agent API (OpenAI-compatible chat completions) with the Agents SDK.
21+
22+
Perplexity's chat completions endpoint is OpenAI-compatible, so the simplest path is to
23+
point an `AsyncOpenAI` client at `https://api.perplexity.ai` and wrap it in a
24+
`ModelProvider` that returns an `OpenAIChatCompletionsModel`.
25+
26+
Set `PERPLEXITY_API_KEY` in your environment before running:
27+
28+
export PERPLEXITY_API_KEY="..."
29+
uv run examples/model_providers/perplexity_provider.py
30+
31+
Docs: https://docs.perplexity.ai/api-reference/chat-completions-post
32+
"""
33+
34+
PERPLEXITY_BASE_URL = "https://api.perplexity.ai"
35+
DEFAULT_MODEL = "sonar-pro"
36+
INTEGRATION_SLUG = "openai-agents"
37+
38+
39+
def _attribution_header() -> str:
40+
try:
41+
version = importlib.metadata.version("openai-agents")
42+
except importlib.metadata.PackageNotFoundError:
43+
version = "unknown"
44+
return f"{INTEGRATION_SLUG}/{version}"
45+
46+
47+
API_KEY = os.environ.get("PERPLEXITY_API_KEY", "")
48+
if not API_KEY:
49+
raise ValueError("Please set PERPLEXITY_API_KEY in your environment.")
50+
51+
52+
client = AsyncOpenAI(
53+
base_url=PERPLEXITY_BASE_URL,
54+
api_key=API_KEY,
55+
default_headers={"X-Pplx-Integration": _attribution_header()},
56+
)
57+
set_tracing_disabled(disabled=True)
58+
59+
60+
class PerplexityProvider(ModelProvider):
61+
def get_model(self, model_name: str | None) -> Model:
62+
return OpenAIChatCompletionsModel(
63+
model=model_name or DEFAULT_MODEL,
64+
openai_client=client,
65+
)
66+
67+
68+
PERPLEXITY_PROVIDER = PerplexityProvider()
69+
70+
71+
@function_tool
72+
def get_weather(city: str) -> str:
73+
print(f"[debug] getting weather for {city}")
74+
return f"The weather in {city} is sunny."
75+
76+
77+
async def main() -> None:
78+
agent = Agent(
79+
name="Assistant",
80+
instructions="You are a helpful research assistant. Cite sources when useful.",
81+
tools=[get_weather],
82+
)
83+
84+
result = await Runner.run(
85+
agent,
86+
"What are the latest developments in quantum computing this week?",
87+
run_config=RunConfig(model_provider=PERPLEXITY_PROVIDER),
88+
)
89+
print(result.final_output)
90+
91+
92+
if __name__ == "__main__":
93+
asyncio.run(main())
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
from __future__ import annotations
2+
3+
import asyncio
4+
import importlib.metadata
5+
import os
6+
7+
import httpx
8+
9+
from agents import Agent, Runner, function_tool, set_tracing_disabled
10+
11+
"""Expose Perplexity's Search API as a function tool.
12+
13+
This shows how to wrap a direct HTTP call to `https://api.perplexity.ai/search` as a
14+
`@function_tool` so any agent can use it. The Search API returns ranked web results
15+
with titles, URLs, snippets, and dates — useful when you want raw search hits rather
16+
than a model-summarised answer.
17+
18+
Set `PERPLEXITY_API_KEY` in your environment before running:
19+
20+
export PERPLEXITY_API_KEY="..."
21+
uv run examples/tools/perplexity_search.py
22+
23+
Docs: https://docs.perplexity.ai/api-reference/search-post
24+
"""
25+
26+
PERPLEXITY_SEARCH_URL = "https://api.perplexity.ai/search"
27+
INTEGRATION_SLUG = "openai-agents"
28+
29+
30+
def _attribution_header() -> str:
31+
try:
32+
version = importlib.metadata.version("openai-agents")
33+
except importlib.metadata.PackageNotFoundError:
34+
version = "unknown"
35+
return f"{INTEGRATION_SLUG}/{version}"
36+
37+
38+
@function_tool
39+
async def perplexity_search(query: str, max_results: int = 5) -> str:
40+
"""Search the web with Perplexity's Search API.
41+
42+
Args:
43+
query: The search query.
44+
max_results: Number of results to return (1-20).
45+
"""
46+
api_key = os.environ.get("PERPLEXITY_API_KEY")
47+
if not api_key:
48+
return "Error: PERPLEXITY_API_KEY is not set."
49+
50+
headers = {
51+
"Authorization": f"Bearer {api_key}",
52+
"Content-Type": "application/json",
53+
"X-Pplx-Integration": _attribution_header(),
54+
}
55+
body = {"query": query, "max_results": max_results}
56+
57+
async with httpx.AsyncClient(timeout=30.0) as client:
58+
response = await client.post(PERPLEXITY_SEARCH_URL, headers=headers, json=body)
59+
response.raise_for_status()
60+
data = response.json()
61+
62+
results = data.get("results", [])
63+
if not results:
64+
return "No results found."
65+
66+
formatted = []
67+
for i, item in enumerate(results, 1):
68+
title = item.get("title", "")
69+
url = item.get("url", "")
70+
snippet = item.get("snippet", "")
71+
formatted.append(f"{i}. {title}\n {url}\n {snippet}")
72+
return "\n\n".join(formatted)
73+
74+
75+
async def main() -> None:
76+
set_tracing_disabled(disabled=True)
77+
agent = Agent(
78+
name="Researcher",
79+
instructions=(
80+
"You are a research assistant. Use the perplexity_search tool to find current "
81+
"information, then summarise the findings and cite the source URLs."
82+
),
83+
tools=[perplexity_search],
84+
)
85+
86+
result = await Runner.run(
87+
agent,
88+
"What were the headline announcements from the latest major AI developer conference?",
89+
)
90+
print(result.final_output)
91+
92+
93+
if __name__ == "__main__":
94+
asyncio.run(main())

0 commit comments

Comments
 (0)