Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/perplexity-search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect/ai-perplexity": minor
---

Add `@effect/ai-perplexity` package providing Effect bindings for the Perplexity Search API.
92 changes: 92 additions & 0 deletions packages/ai/perplexity/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# `@effect/ai-perplexity`

Effect bindings for the [Perplexity Search API](https://docs.perplexity.ai/api-reference/search-post).

## Installation

```sh
pnpm add @effect/ai-perplexity effect
```

## Authentication

The client reads its API key from the `PERPLEXITY_API_KEY` environment
variable, falling back to `PPLX_API_KEY` if the former is not set. You can
obtain a key from the
[Perplexity API key console](https://www.perplexity.ai/account/api/keys).

## Usage

```ts
import { PerplexitySearch } from "@effect/ai-perplexity"
import { Effect, Layer } from "effect"
import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient"

const program = Effect.gen(function*() {
const search = yield* PerplexitySearch.PerplexitySearch
const response = yield* search.search({
query: "latest research on attention mechanisms",
maxResults: 5,
recencyFilter: "month"
})
for (const result of response.results) {
console.log(result.title, result.url)
}
})

const SearchLayer = PerplexitySearch.layerConfig().pipe(
Layer.provide(FetchHttpClient.layer)
)

Effect.runPromise(program.pipe(Effect.provide(SearchLayer)))
```

### Search Options

`PerplexitySearch.search` accepts the following options. All options except
`query` are optional.

| Option | Type | Description |
| ------------------ | ------------------------------------------------ | ------------------------------------------------------------------------------ |
| `query` | `string` | The search query. |
| `maxResults` | `number` | Maximum results to return. Server default is 10. |
| `maxTokensPerPage` | `number` | Maximum tokens per result snippet. |
| `domainFilter` | `ReadonlyArray<string>` | Allowlist (`"nytimes.com"`) or denylist (`"-pinterest.com"`). Cannot be mixed. |
| `recencyFilter` | `"hour" \| "day" \| "week" \| "month" \| "year"` | Restrict results to a recency window. |
| `afterDateFilter` | `string` | Only return results published on or after this date (`m/d/yyyy`). |
| `beforeDateFilter` | `string` | Only return results published on or before this date (`m/d/yyyy`). |

The response is decoded into `SearchResponse`, which exposes a `results` array
of `{ title, url, snippet, date? }` items.

### Domain Filter Caveat

The Perplexity API does not accept a `search_domain_filter` array that mixes
allowed and excluded domains. `PerplexitySearch.search` enforces this by
failing fast with an `AiError` whose reason is `InvalidRequestError` if you pass
an array containing both positive (`"nytimes.com"`) and negative
(`"-pinterest.com"`) entries.

### Manual Layer Composition

If you want to provide the API key explicitly:

```ts
import { PerplexityClient, PerplexitySearch } from "@effect/ai-perplexity"
import { Layer, Redacted } from "effect"
import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient"

const SearchLayer = PerplexitySearch.layer.pipe(
Layer.provide(PerplexityClient.layer({
apiKey: Redacted.make(process.env.PERPLEXITY_API_KEY!)
})),
Layer.provide(FetchHttpClient.layer)
)
```

## Documentation

- [Search API quickstart](https://docs.perplexity.ai/docs/search/quickstart)
- [Search API reference](https://docs.perplexity.ai/api-reference/search-post)
- [Domain filters](https://docs.perplexity.ai/docs/search/filters/domain-filter)
- [Date / recency filters](https://docs.perplexity.ai/docs/search/filters/date-time-filters)
66 changes: 66 additions & 0 deletions packages/ai/perplexity/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"name": "@effect/ai-perplexity",
"version": "4.0.0-beta.1",
"type": "module",
"license": "MIT",
"description": "A Perplexity Search provider integration for Effect AI SDK",
"homepage": "https://effect.website",
"repository": {
"type": "git",
"url": "https://github.com/Effect-TS/effect-smol.git",
"directory": "packages/ai/perplexity"
},
"bugs": {
"url": "https://github.com/Effect-TS/effect-smol/issues"
},
"tags": [
"typescript",
"ai",
"perplexity"
],
"keywords": [
"typescript",
"ai",
"perplexity"
],
"sideEffects": [],
"exports": {
"./package.json": "./package.json",
".": "./src/index.ts",
"./*": "./src/*.ts",
"./internal/*": null,
"./*/index": null
},
"files": [
"src/**/*.ts",
"dist/**/*.js",
"dist/**/*.js.map",
"dist/**/*.d.ts",
"dist/**/*.d.ts.map"
],
"publishConfig": {
"access": "public",
"provenance": true,
"exports": {
"./package.json": "./package.json",
".": "./dist/index.js",
"./*": "./dist/*.js",
"./internal/*": null,
"./*/index": null
}
},
"scripts": {
"build": "tsc -b tsconfig.json && pnpm babel",
"build:tsgo": "tsgo -b tsconfig.json && pnpm babel",
"babel": "babel dist --plugins annotate-pure-calls --out-dir dist --source-maps",
"check": "tsc -b tsconfig.json",
"test": "vitest",
"coverage": "vitest --coverage"
},
"devDependencies": {
"effect": "workspace:^"
},
"peerDependencies": {
"effect": "workspace:^"
}
}
Loading