Perplexity Provider
Perplexity's Agent API (/v1/agent) combines LLM reasoning with real-time
web search, URL fetching, and other native tools, returning cited answers.
Breaking change: as of this release, the Go SDK's Perplexity provider targets the Agent API instead of the pre-migration Sonar Chat Completions API (
/chat/completions). This mirrors an equivalent breaking migration in the upstream TypeScript AI SDK. See Migrating from the Chat Completions API below.
Setup
Installation
import (
"github.com/digitallysavvy/go-ai/pkg/ai"
"github.com/digitallysavvy/go-ai/pkg/providers/perplexity"
)
Configuration
provider := perplexity.New(perplexity.Config{
APIKey: os.Getenv("PERPLEXITY_API_KEY"),
})
model, err := provider.LanguageModel("low")
if err != nil {
log.Fatal(err)
}
The provider sends X-Pplx-Integration: vercel-ai-sdk on every request so
Perplexity can attribute traffic to the SDK; pass your own value in
Config.Headers to override it:
provider := perplexity.New(perplexity.Config{
APIKey: os.Getenv("PERPLEXITY_API_KEY"),
Headers: map[string]string{"X-Pplx-Integration": "my-app"},
})
Get API Key
- Sign up at perplexity.ai
- Get an API key from settings
- Set the environment variable:
export PERPLEXITY_API_KEY=pplx-...
Model Selection
The Agent API accepts either a routing preset or a direct model ID.
Presets
Presets (fast, low, medium, high, xhigh) let Perplexity choose the
underlying model for you, trading off latency/cost against quality:
model, _ := provider.LanguageModel("low")
A preset is sent as {"preset": "low"} in the request body.
Direct model IDs
Any other string (e.g. an upstream model like "openai/gpt-5.1", or a legacy
Sonar model like "sonar-pro") is sent as {"model": "<id>"}:
model, _ := provider.LanguageModel("sonar-pro")
Legacy Sonar model IDs (sonar, sonar-pro, sonar-reasoning,
sonar-reasoning-pro, sonar-deep-research — exposed as
perplexity.ModelSonar, perplexity.ModelSonarPro, etc.) remain valid model
IDs on the Agent API; they are not automatically mapped to a preset.
Provider-Specific Features
Web Search and Citations
Search-augmented answers return citations as source content parts:
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: "What are the latest developments in quantum computing?",
})
for _, part := range result.Content {
if source, ok := part.(types.SourceContent); ok {
fmt.Printf("%s: %s\n", source.Title, source.URL)
}
}
Native Agent API Tools
Enable Perplexity's built-in tools (web_search, fetch_url, people_search,
finance_search, sandbox, mcp, connector) via providerOptions.perplexity.tools:
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: "What's Apple's current stock price?",
ProviderOptions: map[string]interface{}{
"perplexity": map[string]interface{}{
"tools": []interface{}{
map[string]interface{}{"type": "finance_search"},
},
},
},
})
AI SDK Function Tools
Regular AI SDK function tools are also supported and are sent alongside any native tools:
weatherTool := types.Tool{
Name: "weather",
Description: "Get the current weather for a city",
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{"city": map[string]interface{}{"type": "string"}},
"required": []interface{}{"city"},
},
}
Reasoning Effort
Use the standardized Reasoning call option, or set
providerOptions.perplexity.reasoning.effort directly ("minimal", "low",
"medium", "high", or "xhigh") — the provider option takes precedence:
reasoning := types.ReasoningHigh
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: prompt,
Reasoning: &reasoning,
})
Structured Output
response_format with a JSON schema maps to the Agent API's
response_format.json_schema:
result, err := ai.GenerateText(ctx, ai.GenerateTextOptions{
Model: model,
Prompt: prompt,
ResponseFormat: &provider.ResponseFormat{
Type: "json",
Name: "answer",
Schema: mySchema,
},
})
Other Agent API Options
providerOptions.perplexity also accepts: instructions, models (a
fallback model list), max_steps, max_tool_calls, previous_response_id
(continue an earlier Agent API response), store, language_preference, and
skills. Unrecognized keys are forwarded verbatim so new Agent API options
work without an SDK update.
Provider Metadata
result.ProviderMetadata["perplexity"] carries usage/cost details as a
perplexity.PerplexityMetadata value:
if meta, ok := result.ProviderMetadata["perplexity"].(perplexity.PerplexityMetadata); ok {
fmt.Printf("search queries: %v\n", meta.Usage.NumSearchQueries)
if meta.Cost != nil {
fmt.Printf("total cost: %v %v\n", *meta.Cost.TotalCost, *meta.Cost.Currency)
}
for name, tc := range meta.ToolCalls {
fmt.Printf("%s invoked %v times\n", name, *tc.Invocation)
}
}
Image Input
The Agent API accepts image input only — PDFs and other document types supported by the pre-migration Sonar Chat Completions API are rejected:
messages := []types.Message{
{Role: types.RoleUser, Content: []types.ContentPart{
types.TextContent{Text: "Describe this image"},
types.FileContent{MediaType: "image/png", URL: "https://example.com/image.png"},
}},
}
Embeddings
Embeddings are unaffected by the Agent API migration — see
perplexity.PerplexityEmbeddingModelID (pplx-embed-v1-0.6b,
pplx-embed-v1-4b).
Migrating from the Chat Completions API
If you were using the pre-migration Sonar Chat Completions provider, the following changed:
- Endpoint:
/chat/completions→/v1/agent. SupportsTools(),SupportsStructuredOutput(), andSupportsImageInput()now all returntrue(previouslyfalse).providerOptions.perplexity: every field from the old Sonar options (search_recency_filter,search_domain_filter,web_search_options,return_images,return_related_questions,disable_search,reasoning_effort,media_response,stream_mode, etc.) is removed and not aliased. Use the new Agent API option shape (instructions,tools,models,max_steps,max_tool_calls,previous_response_id,store,language_preference,reasoning.effort,skills).PerplexityMetadata(result.ProviderMetadata["perplexity"]) shape changed:Imagesis now alwaysnil(previously populated fromresponse.images; the Agent API does not expose image results through this SDK version).CostgainedCurrency,CacheCreationCost,CacheReadCost, andToolCallsCostfields.- A new
ToolCalls map[string]PerplexityToolCallUsagefield surfaces per-tool invocation counts. Usage.CitationTokensis now alwaysnil(the Agent API does not report a citation-token count);Usage.NumSearchQueriesis now derived fromusage.tool_calls_detailsinstead of a flatnum_search_queriesfield.
- Usage semantics: reasoning tokens are now a subset of
outputTokens.total(standard convention), not additional to it as in the pre-migration Sonar usage shape. - PDF/document input is no longer supported; only images.
- Sources:
result.Contentnow carriestypes.SourceContentparts (withsourceType: "url") built from search results, fetched URLs, and message annotations, instead of a flatCitations []stringlist. - Tool calls and native tool results now appear as ordered
ToolCallContent/SourceContentparts inresult.Content, matching every other tool-calling provider in this SDK.