# 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](#migrating-from-the-chat-completions-api) below.

## Setup

### Installation

```go
import (
    "github.com/digitallysavvy/go-ai/pkg/ai"
    "github.com/digitallysavvy/go-ai/pkg/providers/perplexity"
)
```

### Configuration

```go
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:

```go
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](https://www.perplexity.ai)
2. Get an API key from settings
3. Set the environment variable:

```bash
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:

```go
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>"}`:

```go
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:

```go
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`:

```go
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:

```go
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:

```go
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`:

```go
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:

```go
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:

```go
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

- [API Reference: GenerateText](https://goaisdk.com/docs/reference/ai/generate-text.md)
- [Perplexity Agent API Documentation](https://docs.perplexity.ai)
