Skip to main content

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​

  1. Sign up at perplexity.ai
  2. Get an API key from settings
  3. 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(), and SupportsImageInput() now all return true (previously false).
  • 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:
    • Images is now always nil (previously populated from response.images; the Agent API does not expose image results through this SDK version).
    • Cost gained Currency, CacheCreationCost, CacheReadCost, and ToolCallsCost fields.
    • A new ToolCalls map[string]PerplexityToolCallUsage field surfaces per-tool invocation counts.
    • Usage.CitationTokens is now always nil (the Agent API does not report a citation-token count); Usage.NumSearchQueries is now derived from usage.tool_calls_details instead of a flat num_search_queries field.
  • 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.Content now carries types.SourceContent parts (with sourceType: "url") built from search results, fetched URLs, and message annotations, instead of a flat Citations []string list.
  • Tool calls and native tool results now appear as ordered ToolCallContent / SourceContent parts in result.Content, matching every other tool-calling provider in this SDK.

See Also​