@ai-sdk/perplexity 5.0.14 → 5.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @ai-sdk/perplexity
2
2
 
3
+ ## 5.0.16
4
+
5
+ ### Patch Changes
6
+
7
+ - 0c2a9de: Add `maxOutputTokens` and `reasoning` to experimental decision calls and forward them to language-model-backed decisions. Language-model adapters keep reasoning disabled when omitted. Native decision providers warn when either setting is unsupported.
8
+ - Updated dependencies [0c2a9de]
9
+ - Updated dependencies [200c47f]
10
+ - @ai-sdk/provider@4.0.31
11
+ - @ai-sdk/provider-utils@5.0.64
12
+
13
+ ## 5.0.15
14
+
15
+ ### Patch Changes
16
+
17
+ - 60cc252: feat(perplexity): add decisions api support
18
+ - Updated dependencies [60cc252]
19
+ - @ai-sdk/provider@4.0.30
20
+ - @ai-sdk/provider-utils@5.0.63
21
+
3
22
  ## 5.0.14
4
23
 
5
24
  ### Patch Changes
package/README.md CHANGED
@@ -10,6 +10,7 @@ contains language model support for Perplexity's Agent API, including web search
10
10
  - Direct access to supported third-party models through Perplexity
11
11
  - Native tools for web search, URL fetching, code execution, finance, MCP, and connectors
12
12
  - AI SDK function tools, structured output, reasoning streams, and multi-turn tool calls
13
+ - Native Choice, Score, and Boolean decisions with probability distributions and image input
13
14
 
14
15
  > **Deploying to Vercel?** With Vercel's AI Gateway you can access Perplexity (and hundreds of models from other providers) — no additional packages, API keys, or extra cost. [Get started with AI Gateway](https://vercel.com/ai-gateway).
15
16
 
@@ -58,6 +59,31 @@ Perplexity supports Sonar Chat Completions only until September 27, 2026.
58
59
  Remaining on version 4 will not preserve language generation after that date.
59
60
  Migrate unsupported Sonar features using the alternatives in the migration notes.
60
61
 
62
+ ## Decisions
63
+
64
+ ```ts
65
+ import { perplexity } from '@ai-sdk/perplexity';
66
+ import { experimental_decide as decide } from 'ai';
67
+
68
+ const result = await decide({
69
+ model: perplexity.decisionModel('pplx-decider-latest'),
70
+ state: 'I was charged twice.',
71
+ questions: {
72
+ team: {
73
+ type: 'choice',
74
+ criteria: { billing: 'Payments and refunds', support: 'Other requests' },
75
+ },
76
+ },
77
+ });
78
+
79
+ console.log(result.answers.team.choice);
80
+ console.log(result.answers.team.probabilities);
81
+ ```
82
+
83
+ See [decision model documentation](https://ai-sdk.dev/providers/ai-sdk-providers/perplexity#decision-models)
84
+ for optional instructions, structured criteria, single-level Score rubrics,
85
+ images, limits, and provider metadata.
86
+
61
87
  ## Documentation
62
88
 
63
89
  Please check out the **[Perplexity provider documentation](https://ai-sdk.dev/providers/ai-sdk-providers/perplexity)** for more information.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,11 @@
1
- import { EmbeddingModelV4, LanguageModelV4, ProviderV4 } from "@ai-sdk/provider";
1
+ import { EmbeddingModelV4, Experimental_DecisionModelV4, LanguageModelV4, ProviderV4 } from "@ai-sdk/provider";
2
2
  import { FetchFunction } from "@ai-sdk/provider-utils";
3
3
  import { z } from "zod/v4";
4
+ //#region src/perplexity-decision-model-options.d.ts
5
+ type PerplexityDecisionModelId = 'pplx-decider-v1.2' | 'pplx-decider-flash-v1.2' | 'pplx-decider-latest' | 'pplx-decider-flash-latest' | 'perplexity/pplx-decider-latest' | 'perplexity/pplx-decider-flash-latest' | 'pplx-decider-v1.1-27b' | 'pplx-decider-v1-27b' | (string & {});
6
+ /** Perplexity decision models do not support provider-specific options. */
7
+ type PerplexityDecisionModelOptions = Record<string, never>;
8
+ //#endregion
4
9
  //#region src/perplexity-embedding-model-options.d.ts
5
10
  type PerplexityEmbeddingModelId = 'pplx-embed-v1-0.6b' | 'pplx-embed-v1-4b' | (string & {});
6
11
  declare const perplexityEmbeddingModelOptions: z.ZodObject<{
@@ -18,6 +23,8 @@ type PerplexityLanguageModelId = PerplexityAgentPreset | 'perplexity/sonar' | (s
18
23
  //#endregion
19
24
  //#region src/perplexity-provider.d.ts
20
25
  interface PerplexityProvider extends ProviderV4 {
26
+ /** Creates an experimental decision model using the Perplexity Decisions API. */
27
+ decisionModel(modelId: PerplexityDecisionModelId): Experimental_DecisionModelV4;
21
28
  /**
22
29
  * Creates a Perplexity Agent API model or preset for text generation.
23
30
  */
@@ -171,5 +178,5 @@ type PerplexityLanguageModelOptions = z.infer<typeof perplexityLanguageModelOpti
171
178
  //#region src/version.d.ts
172
179
  export declare const VERSION: string;
173
180
  //#endregion
174
- export type { PerplexityAgentPreset, PerplexityEmbeddingModelId, PerplexityEmbeddingModelOptions, PerplexityLanguageModelId, PerplexityLanguageModelOptions, PerplexityProvider, PerplexityProviderSettings };
181
+ export type { PerplexityAgentPreset, PerplexityDecisionModelId, PerplexityDecisionModelOptions, PerplexityEmbeddingModelId, PerplexityEmbeddingModelOptions, PerplexityLanguageModelId, PerplexityLanguageModelOptions, PerplexityProvider, PerplexityProviderSettings };
175
182
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/perplexity-embedding-model-options.ts","../src/perplexity-options.ts","../src/perplexity-provider.ts","../src/perplexity-language-model-options.ts","../src/version.ts"],"mappings":";;;;KAGY;cAKC,iCAA+B,EAAA;;;;;;GAe1C,EAAA,KAAA;KAEU,kCAAkC,EAAE,aACvC;;;KC1BG;KAOA,4BACR;;;UCWa,2BAA2B;;;;GAIzC,SAAS,4BAA4B;;;;EAKtC,cAAc,SAAS,4BAA4B;;;;EAKnD,UAAU,SAAS,6BAA6B;;;;EAKhD,eAAe,SAAS,6BAA6B;;;;EAKrD,mBAAmB,SAAS,6BAA6B;;UAG1C;;;;EAIf;;;;EAKA;;;;EAKA,UAAU;;;;;EAMV,QAAQ;;wBAGM,iBACd,UAAS,6BACR;qBAoDU,YAAU;;;cCjEV,gCAA8B,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DzC,EAAA,KAAA;KAEU,iCAAiC,EAAE,aACtC;;;qBCxHI"}
1
+ {"version":3,"file":"index.d.ts","names":["DecisionModelV4"],"sources":["../src/perplexity-decision-model-options.ts","../src/perplexity-embedding-model-options.ts","../src/perplexity-options.ts","../src/perplexity-provider.ts","../src/perplexity-language-model-options.ts","../src/version.ts"],"mappings":";;;;KAAY;;KAYA,iCAAiC;;;KCTjC;cAKC,iCAA+B,EAAA;;;;;;GAe1C,EAAA,KAAA;KAEU,kCAAkC,EAAE,aACvC;;;KC1BG;KAOA,4BACR;;;UCca,2BAA2B;;EAE1C,cAAc,SAAS,4BAA4BA;;;;GAKlD,SAAS,4BAA4B;;;;EAKtC,cAAc,SAAS,4BAA4B;;;;EAKnD,UAAU,SAAS,6BAA6B;;;;EAKhD,eAAe,SAAS,6BAA6B;;;;EAKrD,mBAAmB,SAAS,6BAA6B;;UAG1C;;;;EAIf;;;;EAKA;;;;EAKA,UAAU;;;;;EAMV,QAAQ;;wBAGM,iBACd,UAAS,6BACR;qBA2DU,YAAU;;;cC9EV,gCAA8B,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DzC,EAAA,KAAA;KAEU,iCAAiC,EAAE,aACtC;;;qBCxHI"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { APICallError, NoSuchModelError, TooManyEmbeddingValuesForCallError, UnsupportedFunctionalityError } from "@ai-sdk/provider";
2
- import { WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE, combineHeaders, convertBase64ToUint8Array, convertUint8ArrayToBase64, createEventSourceResponseHandler, createJsonErrorResponseHandler, createJsonResponseHandler, createLanguageModelResponseMetadata, createNullLanguageModelUsage, generateId, getTopLevelMediaType, isCustomReasoning, loadApiKey, mapReasoningToProviderEffort, parseProviderOptions, postJsonToApi, resolveFullMediaType, serializeModelOptions, withUserAgentSuffix, withoutTrailingSlash } from "@ai-sdk/provider-utils";
1
+ import { APICallError, Experimental_DecisionUnsupportedQuestionTypeError, InvalidArgumentError, InvalidResponseDataError, NoSuchModelError, TooManyEmbeddingValuesForCallError, UnsupportedFunctionalityError } from "@ai-sdk/provider";
2
+ import { WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE, combineHeaders, convertBase64ToUint8Array, convertUint8ArrayToBase64, createEventSourceResponseHandler, createJsonErrorResponseHandler, createJsonResponseHandler, createLanguageModelResponseMetadata, createNullLanguageModelUsage, detectMediaType, generateId, getTopLevelMediaType, isCustomReasoning, isFullMediaType, loadApiKey, mapReasoningToProviderEffort, parseProviderOptions, postJsonToApi, resolve, resolveFullMediaType, serializeModelOptions, withUserAgentSuffix, withoutTrailingSlash } from "@ai-sdk/provider-utils";
3
3
  import { z } from "zod/v4";
4
4
  //#region src/perplexity-embedding-model-options.ts
5
5
  const perplexityEmbeddingModelOptions = z.object({
@@ -290,7 +290,7 @@ const perplexityAgentChunkSchema = z.looseObject({
290
290
  });
291
291
  const perplexityErrorSchema = z.looseObject({
292
292
  error: z.union([z.string(), z.looseObject({
293
- code: z.union([z.string(), z.number()]).optional(),
293
+ code: z.union([z.string(), z.number()]).nullish(),
294
294
  message: z.string().nullish(),
295
295
  type: z.string().nullish()
296
296
  })]).optional(),
@@ -1090,8 +1090,214 @@ const perplexityEmbeddingResponseSchema = z.object({
1090
1090
  }).nullish()
1091
1091
  });
1092
1092
  //#endregion
1093
+ //#region src/convert-to-perplexity-decision-state.ts
1094
+ function convertToPerplexityDecisionState(state) {
1095
+ const parts = state.map((part) => {
1096
+ switch (part.type) {
1097
+ case "text": return part.text;
1098
+ case "json": return part.value;
1099
+ case "file": {
1100
+ if (part.data.type !== "data") throw new UnsupportedFunctionalityError({ functionality: `Perplexity decision file input: ${part.data.type}` });
1101
+ const mediaType = isFullMediaType(part.mediaType) ? part.mediaType : detectMediaType({
1102
+ data: part.data.data,
1103
+ topLevelType: "image"
1104
+ });
1105
+ if (![
1106
+ "image/png",
1107
+ "image/jpeg",
1108
+ "image/webp"
1109
+ ].includes(mediaType ?? "")) throw new UnsupportedFunctionalityError({ functionality: `Perplexity decision image media type: ${part.mediaType}` });
1110
+ return {
1111
+ type: "image_url",
1112
+ image_url: { url: `data:${mediaType};base64,${typeof part.data.data === "string" ? part.data.data : convertUint8ArrayToBase64(part.data.data)}` }
1113
+ };
1114
+ }
1115
+ }
1116
+ });
1117
+ if (countImages(parts) > 8) throw new InvalidArgumentError({
1118
+ argument: "state",
1119
+ message: "Perplexity Decisions supports at most 8 images in the shared state."
1120
+ });
1121
+ const single = parts[0];
1122
+ return parts.length === 1 && single !== null && (typeof single === "string" || typeof single === "object") ? single : parts;
1123
+ }
1124
+ function countImages(value) {
1125
+ if (Array.isArray(value)) return value.reduce((count, item) => count + countImages(item), 0);
1126
+ if (value === null || typeof value !== "object") return 0;
1127
+ const object = value;
1128
+ if (object.type === "image_url") {
1129
+ const image = object.image_url;
1130
+ if (image == null || typeof image !== "object" || Array.isArray(image) || typeof image.url !== "string" || !/^data:image\/(png|jpeg|webp);base64,/i.test(image.url)) throw new UnsupportedFunctionalityError({ functionality: "Perplexity decision images require PNG, JPEG, or WebP base64 data URLs" });
1131
+ return 1;
1132
+ }
1133
+ return Object.values(value).reduce((count, item) => count + (item === void 0 ? 0 : countImages(item)), 0);
1134
+ }
1135
+ //#endregion
1136
+ //#region src/perplexity-decision-model.ts
1137
+ var DecisionPerplexityModel = class DecisionPerplexityModel {
1138
+ constructor(modelId, config) {
1139
+ this.modelId = modelId;
1140
+ this.config = config;
1141
+ this.specificationVersion = "v4";
1142
+ this.supportedQuestionTypes = [
1143
+ "choice",
1144
+ "score",
1145
+ "boolean"
1146
+ ];
1147
+ }
1148
+ get provider() {
1149
+ return this.config.provider;
1150
+ }
1151
+ static [WORKFLOW_SERIALIZE](model) {
1152
+ return serializeModelOptions({
1153
+ modelId: model.modelId,
1154
+ config: model.config
1155
+ });
1156
+ }
1157
+ static [WORKFLOW_DESERIALIZE](options) {
1158
+ return new DecisionPerplexityModel(options.modelId, options.config);
1159
+ }
1160
+ async doDecide({ state, questions, maxOutputTokens, reasoning, headers, abortSignal, providerOptions }) {
1161
+ const entries = Object.entries(questions);
1162
+ if (entries.length === 0 || entries.length > 128) throw new InvalidArgumentError({
1163
+ argument: "questions",
1164
+ message: "Perplexity Decisions supports 1 to 128 questions per request."
1165
+ });
1166
+ const nativeQuestions = Object.fromEntries(entries.map(([id, question]) => {
1167
+ if (id.length === 0) throw new InvalidArgumentError({
1168
+ argument: "questions",
1169
+ message: "Perplexity Decisions requires non-empty question names."
1170
+ });
1171
+ switch (question.type) {
1172
+ case "boolean": return [id, {
1173
+ type: "noul",
1174
+ instructions: question.instructions,
1175
+ criteria: question.criteria
1176
+ }];
1177
+ case "choice": {
1178
+ const count = Object.keys(question.criteria).length;
1179
+ if (count === 0 || count > 255) throw new InvalidArgumentError({
1180
+ argument: `questions.${id}.criteria`,
1181
+ message: "Perplexity Choice questions support 1 to 255 options."
1182
+ });
1183
+ return [id, {
1184
+ type: "choice",
1185
+ instructions: question.instructions,
1186
+ criteria: question.criteria
1187
+ }];
1188
+ }
1189
+ case "score":
1190
+ if (question.criteria.length === 0 || question.criteria.length > 10 || question.criteria.some((level) => level === null)) throw new InvalidArgumentError({
1191
+ argument: `questions.${id}.criteria`,
1192
+ message: "Perplexity Score questions require 1 to 10 non-null levels."
1193
+ });
1194
+ return [id, {
1195
+ type: "score",
1196
+ instructions: question.instructions,
1197
+ criteria: question.criteria
1198
+ }];
1199
+ default: throw new Experimental_DecisionUnsupportedQuestionTypeError({
1200
+ questionId: id,
1201
+ questionType: question.type,
1202
+ provider: this.provider,
1203
+ modelId: this.modelId
1204
+ });
1205
+ }
1206
+ }));
1207
+ const { value: response, rawValue, responseHeaders } = await postJsonToApi({
1208
+ url: `${this.config.baseURL}/v1/decisions`,
1209
+ headers: combineHeaders(await resolve(this.config.headers), headers),
1210
+ body: {
1211
+ model: this.modelId,
1212
+ state: convertToPerplexityDecisionState(state),
1213
+ questions: nativeQuestions
1214
+ },
1215
+ abortSignal,
1216
+ fetch: this.config.fetch,
1217
+ failedResponseHandler: createJsonErrorResponseHandler({
1218
+ errorSchema: perplexityErrorSchema,
1219
+ errorToMessage: perplexityErrorToMessage
1220
+ }),
1221
+ successfulResponseHandler: createJsonResponseHandler(perplexityDecisionResponseSchema)
1222
+ });
1223
+ if (Object.keys(response.answers).length !== entries.length || entries.some(([id]) => !Object.prototype.hasOwnProperty.call(response.answers, id))) throw new InvalidResponseDataError({
1224
+ data: rawValue,
1225
+ message: "Perplexity Decisions must return exactly one answer for every question."
1226
+ });
1227
+ return {
1228
+ answers: Object.fromEntries(Object.entries(response.answers).map(([id, answer]) => [id, answer.type === "noul" ? {
1229
+ type: "boolean",
1230
+ probability: answer.noul
1231
+ } : answer.type === "choice" ? {
1232
+ type: "choice",
1233
+ choice: answer.choice,
1234
+ probabilities: answer.probabilities
1235
+ } : {
1236
+ type: "score",
1237
+ score: answer.score,
1238
+ probabilities: answer.probabilities
1239
+ }])),
1240
+ usage: response.usage == null ? void 0 : {
1241
+ inputTokens: response.usage.input_tokens ?? void 0,
1242
+ outputTokens: response.usage.output_tokens ?? void 0
1243
+ },
1244
+ warnings: [
1245
+ ...maxOutputTokens != null ? [{
1246
+ type: "unsupported",
1247
+ feature: "maxOutputTokens"
1248
+ }] : [],
1249
+ ...reasoning != null ? [{
1250
+ type: "unsupported",
1251
+ feature: "reasoning"
1252
+ }] : [],
1253
+ ...Object.keys(providerOptions?.perplexity ?? {}).map((option) => ({
1254
+ type: "unsupported",
1255
+ feature: `providerOptions.perplexity.${option}`
1256
+ }))
1257
+ ],
1258
+ providerMetadata: { perplexity: {
1259
+ confidence: Object.fromEntries(Object.entries(response.answers).flatMap(([id, answer]) => answer.type !== "noul" && answer.confidence != null ? [[id, answer.confidence]] : [])),
1260
+ legend: Object.fromEntries(Object.entries(response.answers).flatMap(([id, answer]) => answer.type === "score" && answer.legend != null ? [[id, answer.legend]] : []))
1261
+ } },
1262
+ response: {
1263
+ id: responseHeaders?.["x-request-id"],
1264
+ modelId: response.model ?? this.modelId,
1265
+ headers: responseHeaders,
1266
+ body: rawValue
1267
+ }
1268
+ };
1269
+ }
1270
+ };
1271
+ const probability = z.number().min(0).max(1);
1272
+ const perplexityDecisionResponseSchema = z.object({
1273
+ model: z.string().nullish(),
1274
+ answers: z.record(z.string(), z.discriminatedUnion("type", [
1275
+ z.object({
1276
+ type: z.literal("noul"),
1277
+ noul: probability
1278
+ }),
1279
+ z.object({
1280
+ type: z.literal("choice"),
1281
+ choice: z.string(),
1282
+ probabilities: z.record(z.string(), probability),
1283
+ confidence: probability.nullish()
1284
+ }),
1285
+ z.object({
1286
+ type: z.literal("score"),
1287
+ score: z.number(),
1288
+ probabilities: z.record(z.string(), probability),
1289
+ confidence: probability.nullish(),
1290
+ legend: z.record(z.string(), z.json()).nullish()
1291
+ })
1292
+ ])),
1293
+ usage: z.object({
1294
+ input_tokens: z.number().nullish(),
1295
+ output_tokens: z.number().nullish()
1296
+ }).nullish()
1297
+ });
1298
+ //#endregion
1093
1299
  //#region src/version.ts
1094
- const VERSION = "5.0.14";
1300
+ const VERSION = "5.0.16";
1095
1301
  //#endregion
1096
1302
  //#region src/perplexity-provider.ts
1097
1303
  function createPerplexity(options = {}) {
@@ -1122,6 +1328,12 @@ function createPerplexity(options = {}) {
1122
1328
  const provider = (modelId) => createLanguageModel(modelId);
1123
1329
  provider.specificationVersion = "v4";
1124
1330
  provider.languageModel = createLanguageModel;
1331
+ provider.decisionModel = (modelId) => new DecisionPerplexityModel(modelId, {
1332
+ provider: "perplexity.decision",
1333
+ baseURL,
1334
+ headers: getHeaders,
1335
+ fetch: options.fetch
1336
+ });
1125
1337
  provider.embedding = createEmbeddingModel;
1126
1338
  provider.embeddingModel = createEmbeddingModel;
1127
1339
  provider.textEmbeddingModel = createEmbeddingModel;