@ai-sdk/perplexity 4.0.50 → 5.0.0

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/dist/index.js CHANGED
@@ -45,49 +45,51 @@ var perplexityEmbeddingModelOptions = z.object({
45
45
  });
46
46
 
47
47
  // src/perplexity-language-model.ts
48
+ import {
49
+ APICallError
50
+ } from "@ai-sdk/provider";
48
51
  import {
49
52
  combineHeaders,
50
53
  createEventSourceResponseHandler,
51
54
  createJsonErrorResponseHandler,
52
55
  createJsonResponseHandler,
53
- createLanguageModelResponseMetadata as getResponseMetadata,
56
+ createLanguageModelResponseMetadata,
54
57
  isCustomReasoning,
55
58
  parseProviderOptions,
56
59
  postJsonToApi,
57
60
  serializeModelOptions,
58
- WORKFLOW_SERIALIZE,
59
- WORKFLOW_DESERIALIZE
61
+ WORKFLOW_DESERIALIZE,
62
+ WORKFLOW_SERIALIZE
60
63
  } from "@ai-sdk/provider-utils";
61
- import { z as z3 } from "zod/v4";
62
64
 
63
65
  // src/convert-perplexity-usage.ts
64
66
  import { createNullLanguageModelUsage } from "@ai-sdk/provider-utils";
65
67
  function convertPerplexityUsage(usage) {
66
- var _a, _b, _c;
67
68
  if (usage == null) {
68
69
  return createNullLanguageModelUsage();
69
70
  }
70
- const promptTokens = (_a = usage.prompt_tokens) != null ? _a : 0;
71
- const completionTokens = (_b = usage.completion_tokens) != null ? _b : 0;
72
- const reasoningTokens = (_c = usage.reasoning_tokens) != null ? _c : 0;
71
+ const inputTokens = usage.input_tokens ?? 0;
72
+ const outputTokens = usage.output_tokens ?? 0;
73
+ const cacheReadTokens = usage.input_tokens_details?.cache_read_input_tokens ?? usage.input_tokens_details?.cached_tokens ?? 0;
74
+ const cacheWriteTokens = usage.input_tokens_details?.cache_creation_input_tokens ?? 0;
75
+ const reasoningTokens = usage.output_tokens_details?.reasoning_tokens ?? 0;
73
76
  return {
74
77
  inputTokens: {
75
- total: promptTokens,
76
- noCache: promptTokens,
77
- cacheRead: void 0,
78
- cacheWrite: void 0
78
+ total: inputTokens,
79
+ noCache: Math.max(0, inputTokens - cacheReadTokens - cacheWriteTokens),
80
+ cacheRead: cacheReadTokens,
81
+ cacheWrite: cacheWriteTokens
79
82
  },
80
83
  outputTokens: {
81
- // Perplexity reports reasoning tokens separately from completion tokens.
82
- total: completionTokens + reasoningTokens,
83
- text: completionTokens,
84
+ total: outputTokens,
85
+ text: Math.max(0, outputTokens - reasoningTokens),
84
86
  reasoning: reasoningTokens
85
87
  },
86
88
  raw: usage
87
89
  };
88
90
  }
89
91
 
90
- // src/convert-to-perplexity-messages.ts
92
+ // src/convert-to-perplexity-input.ts
91
93
  import {
92
94
  UnsupportedFunctionalityError
93
95
  } from "@ai-sdk/provider";
@@ -96,95 +98,154 @@ import {
96
98
  getTopLevelMediaType,
97
99
  resolveFullMediaType
98
100
  } from "@ai-sdk/provider-utils";
99
- function convertToPerplexityMessages(prompt) {
100
- const messages = [];
101
+ function serializeToolOutput(output) {
102
+ switch (output.type) {
103
+ case "text":
104
+ case "error-text":
105
+ return output.value;
106
+ case "json":
107
+ case "error-json":
108
+ return JSON.stringify(output.value);
109
+ case "execution-denied":
110
+ return output.reason ?? "Tool call execution denied.";
111
+ case "content": {
112
+ if (output.value.some((part) => part.type !== "text")) {
113
+ throw new UnsupportedFunctionalityError({
114
+ functionality: "file and custom tool result content"
115
+ });
116
+ }
117
+ return output.value.map((part) => part.type === "text" ? part.text : "").join("");
118
+ }
119
+ default: {
120
+ const _exhaustiveCheck = output;
121
+ throw new Error(`Unsupported tool output: ${_exhaustiveCheck}`);
122
+ }
123
+ }
124
+ }
125
+ function getThoughtSignature(providerOptions) {
126
+ const thoughtSignature = providerOptions?.perplexity?.thoughtSignature;
127
+ return typeof thoughtSignature === "string" ? thoughtSignature : void 0;
128
+ }
129
+ function convertToPerplexityInput(prompt) {
130
+ const input = [];
131
+ const warnings = [];
101
132
  for (const { role, content } of prompt) {
102
133
  switch (role) {
103
134
  case "system": {
104
- messages.push({ role: "system", content });
135
+ input.push({ type: "message", role: "system", content });
105
136
  break;
106
137
  }
107
- case "user":
108
- case "assistant": {
109
- const hasMultipartContent = content.some(
110
- (part) => part.type === "file" && getTopLevelMediaType(part.mediaType) === "image" || part.type === "file" && getTopLevelMediaType(part.mediaType) === "application"
111
- );
112
- const messageContent = content.map((part, index) => {
113
- switch (part.type) {
114
- case "text": {
115
- return {
116
- type: "text",
117
- text: part.text
118
- };
119
- }
120
- case "file": {
121
- switch (part.data.type) {
122
- case "reference": {
138
+ case "user": {
139
+ const convertedContent = content.map(
140
+ (part) => {
141
+ switch (part.type) {
142
+ case "text":
143
+ return { type: "input_text", text: part.text };
144
+ case "file": {
145
+ if (getTopLevelMediaType(part.mediaType) !== "image") {
123
146
  throw new UnsupportedFunctionalityError({
124
- functionality: "file parts with provider references"
125
- });
126
- }
127
- case "text": {
128
- throw new UnsupportedFunctionalityError({
129
- functionality: "text file parts"
147
+ functionality: `file part media type ${part.mediaType}`
130
148
  });
131
149
  }
132
- case "url":
133
- case "data": {
134
- const topLevelMediaType = getTopLevelMediaType(
135
- part.mediaType
136
- );
137
- if (topLevelMediaType === "application") {
138
- const fullMediaType = resolveFullMediaType({ part });
139
- if (fullMediaType !== "application/pdf") {
140
- throw new UnsupportedFunctionalityError({
141
- functionality: `file part media type ${fullMediaType}`
142
- });
143
- }
144
- return part.data.type === "url" ? {
145
- type: "file_url",
146
- file_url: {
147
- url: part.data.url.toString()
148
- },
149
- file_name: part.filename
150
- } : {
151
- type: "file_url",
152
- file_url: {
153
- url: typeof part.data.data === "string" ? part.data.data : convertUint8ArrayToBase64(part.data.data)
154
- },
155
- file_name: part.filename || `document-${index}.pdf`
150
+ switch (part.data.type) {
151
+ case "url":
152
+ return {
153
+ type: "input_image",
154
+ image_url: part.data.url.toString()
156
155
  };
157
- } else if (topLevelMediaType === "image") {
158
- return part.data.type === "url" ? {
159
- type: "image_url",
160
- image_url: {
161
- url: part.data.url.toString()
162
- }
163
- } : {
164
- type: "image_url",
165
- image_url: {
166
- url: `data:${resolveFullMediaType({ part })};base64,${typeof part.data.data === "string" ? part.data.data : convertUint8ArrayToBase64(part.data.data)}`
167
- }
156
+ case "data":
157
+ return {
158
+ type: "input_image",
159
+ image_url: `data:${resolveFullMediaType({ part })};base64,${typeof part.data.data === "string" ? part.data.data : convertUint8ArrayToBase64(part.data.data)}`
168
160
  };
169
- }
170
- throw new UnsupportedFunctionalityError({
171
- functionality: `file part media type ${part.mediaType}`
172
- });
161
+ case "reference":
162
+ throw new UnsupportedFunctionalityError({
163
+ functionality: "file parts with provider references"
164
+ });
165
+ case "text":
166
+ throw new UnsupportedFunctionalityError({
167
+ functionality: "text file parts"
168
+ });
173
169
  }
174
170
  }
175
171
  }
176
172
  }
177
- }).filter(Boolean);
178
- messages.push({
179
- role,
180
- content: hasMultipartContent ? messageContent : messageContent.filter((part) => part.type === "text").map((part) => part.text).join("")
173
+ );
174
+ const isTextOnly = convertedContent.every(
175
+ (part) => part.type === "input_text"
176
+ );
177
+ input.push({
178
+ type: "message",
179
+ role: "user",
180
+ content: isTextOnly ? convertedContent.map((part) => part.type === "input_text" ? part.text : "").join("") : convertedContent
181
181
  });
182
182
  break;
183
183
  }
184
+ case "assistant": {
185
+ const text = content.filter((part) => part.type === "text").map((part) => part.text).join("");
186
+ if (text.length > 0) {
187
+ input.push({ type: "message", role: "assistant", content: text });
188
+ }
189
+ for (const part of content) {
190
+ switch (part.type) {
191
+ case "text":
192
+ break;
193
+ case "tool-call":
194
+ input.push({
195
+ type: "function_call",
196
+ call_id: part.toolCallId,
197
+ name: part.toolName,
198
+ arguments: JSON.stringify(part.input ?? {}),
199
+ thought_signature: getThoughtSignature(part.providerOptions)
200
+ });
201
+ break;
202
+ case "tool-result":
203
+ input.push({
204
+ type: "function_call_output",
205
+ call_id: part.toolCallId,
206
+ name: part.toolName,
207
+ output: serializeToolOutput(part.output),
208
+ thought_signature: getThoughtSignature(part.providerOptions)
209
+ });
210
+ break;
211
+ case "reasoning":
212
+ warnings.push({
213
+ type: "unsupported",
214
+ feature: "reasoning content in prompt"
215
+ });
216
+ break;
217
+ case "file":
218
+ case "reasoning-file":
219
+ case "custom":
220
+ throw new UnsupportedFunctionalityError({
221
+ functionality: `assistant ${part.type} parts`
222
+ });
223
+ default: {
224
+ const _exhaustiveCheck = part;
225
+ throw new Error(
226
+ `Unsupported assistant part: ${_exhaustiveCheck}`
227
+ );
228
+ }
229
+ }
230
+ }
231
+ break;
232
+ }
184
233
  case "tool": {
185
- throw new UnsupportedFunctionalityError({
186
- functionality: "Tool messages"
187
- });
234
+ for (const part of content) {
235
+ if (part.type === "tool-approval-response") {
236
+ throw new UnsupportedFunctionalityError({
237
+ functionality: "tool approval responses"
238
+ });
239
+ }
240
+ input.push({
241
+ type: "function_call_output",
242
+ call_id: part.toolCallId,
243
+ name: part.toolName,
244
+ output: serializeToolOutput(part.output),
245
+ thought_signature: getThoughtSignature(part.providerOptions)
246
+ });
247
+ }
248
+ break;
188
249
  }
189
250
  default: {
190
251
  const _exhaustiveCheck = role;
@@ -192,141 +253,420 @@ function convertToPerplexityMessages(prompt) {
192
253
  }
193
254
  }
194
255
  }
195
- return messages;
256
+ return { input, warnings };
196
257
  }
197
258
 
198
259
  // src/map-perplexity-finish-reason.ts
199
- function mapPerplexityFinishReason(finishReason) {
200
- switch (finishReason) {
201
- case "stop":
202
- case "length":
203
- return finishReason;
260
+ function mapPerplexityFinishReason({
261
+ status,
262
+ incompleteReason,
263
+ hasFunctionCall
264
+ }) {
265
+ switch (incompleteReason) {
266
+ case "max_output_tokens":
267
+ return "length";
268
+ case "content_filter":
269
+ return "content-filter";
270
+ }
271
+ switch (status) {
272
+ case "completed":
273
+ return hasFunctionCall ? "tool-calls" : "stop";
274
+ case "requires_action":
275
+ return "tool-calls";
276
+ case "failed":
277
+ return "error";
278
+ case "cancelled":
279
+ case "queued":
280
+ case "in_progress":
204
281
  default:
205
- return "other";
282
+ return hasFunctionCall ? "tool-calls" : "other";
206
283
  }
207
284
  }
208
285
 
209
- // src/perplexity-language-model-options.ts
286
+ // src/perplexity-agent-api.ts
210
287
  import { z as z2 } from "zod/v4";
211
- var perplexityLanguageModelOptions = z2.looseObject({
212
- /**
213
- * Filters search results to those published within the specified time window.
214
- * Cannot be combined with other date filters.
215
- */
216
- search_recency_filter: z2.enum(["hour", "day", "week", "month", "year"]).optional(),
217
- /**
218
- * Restrict web search results to specific domains or URLs.
219
- * Prefix a domain with "-" to exclude it.
220
- */
221
- search_domain_filter: z2.array(z2.string()).optional(),
222
- /**
223
- * Filter search results by language using ISO 639-1 codes.
224
- */
225
- search_language_filter: z2.array(z2.string()).optional(),
226
- /**
227
- * Return search results published after this date.
228
- */
229
- search_after_date_filter: z2.string().optional(),
230
- /**
231
- * Return search results published before this date.
232
- */
233
- search_before_date_filter: z2.string().optional(),
234
- /**
235
- * Return search results last updated after this date.
236
- */
237
- last_updated_after_filter: z2.string().optional(),
238
- /**
239
- * Return search results last updated before this date.
240
- */
241
- last_updated_before_filter: z2.string().optional(),
242
- /**
243
- * Source of search results.
244
- */
245
- search_mode: z2.enum(["web", "academic", "sec"]).optional(),
246
- /**
247
- * If true, the model decides whether web search is needed.
248
- */
249
- enable_search_classifier: z2.boolean().optional(),
250
- /**
251
- * If true, disables web search.
252
- */
253
- disable_search: z2.boolean().optional(),
254
- /**
255
- * If true, a list of related questions is included in the response.
256
- */
257
- return_related_questions: z2.boolean().optional(),
258
- /**
259
- * If true, image search results are included in the response.
260
- */
261
- return_images: z2.boolean().optional(),
262
- /**
263
- * Restrict image results to specific domains.
264
- * Prefix a domain with "-" to exclude it.
265
- */
266
- image_domain_filter: z2.array(z2.string()).optional(),
288
+ var perplexitySearchResultSchema = z2.looseObject({
289
+ id: z2.number().optional(),
290
+ title: z2.string(),
291
+ url: z2.string(),
292
+ snippet: z2.string().optional(),
293
+ date: z2.string().nullish(),
294
+ last_updated: z2.string().nullish(),
295
+ source: z2.string().optional()
296
+ });
297
+ var perplexityFetchedContentSchema = z2.looseObject({
298
+ title: z2.string(),
299
+ url: z2.string(),
300
+ snippet: z2.string().optional()
301
+ });
302
+ var perplexityContentPartSchema = z2.looseObject({
303
+ type: z2.string(),
304
+ text: z2.string().optional(),
305
+ annotations: z2.array(
306
+ z2.looseObject({
307
+ type: z2.string().optional(),
308
+ url: z2.string().optional(),
309
+ title: z2.string().optional()
310
+ })
311
+ ).nullish()
312
+ });
313
+ var handledOutputTypes = [
314
+ "message",
315
+ "search_results",
316
+ "fetch_url_results",
317
+ "function_call"
318
+ ];
319
+ var perplexityOutputItemSchema = z2.union([
320
+ z2.looseObject({
321
+ type: z2.literal("message"),
322
+ id: z2.string().nullish(),
323
+ content: z2.array(perplexityContentPartSchema).nullish()
324
+ }),
325
+ z2.looseObject({
326
+ type: z2.literal("search_results"),
327
+ results: z2.array(perplexitySearchResultSchema).nullish()
328
+ }),
329
+ z2.looseObject({
330
+ type: z2.literal("fetch_url_results"),
331
+ contents: z2.array(perplexityFetchedContentSchema).nullish()
332
+ }),
333
+ z2.looseObject({
334
+ type: z2.literal("function_call"),
335
+ id: z2.string().nullish(),
336
+ call_id: z2.string().nullish(),
337
+ name: z2.string().nullish(),
338
+ arguments: z2.string().nullish(),
339
+ thought_signature: z2.string().nullish()
340
+ }),
341
+ // Native tool traces remain available in raw responses and raw stream chunks.
342
+ // Their fields (e.g. finance_results.results) have different shapes. Do not
343
+ // validate them as search results, or let malformed handled items fall back.
344
+ z2.object({
345
+ type: z2.string().refine((type) => !handledOutputTypes.includes(type))
346
+ }).transform(() => ({ type: "unhandled" }))
347
+ ]);
348
+ var perplexityCostSchema = z2.looseObject({
349
+ currency: z2.string().optional(),
350
+ input_cost: z2.number().optional(),
351
+ output_cost: z2.number().optional(),
352
+ total_cost: z2.number().optional(),
353
+ cache_creation_cost: z2.number().nullish(),
354
+ cache_read_cost: z2.number().nullish(),
355
+ tool_calls_cost: z2.number().nullish()
356
+ });
357
+ var perplexityUsageSchema = z2.looseObject({
358
+ input_tokens: z2.number(),
359
+ output_tokens: z2.number(),
360
+ total_tokens: z2.number(),
361
+ input_tokens_details: z2.looseObject({
362
+ cached_tokens: z2.number().optional(),
363
+ cache_creation_input_tokens: z2.number().optional(),
364
+ cache_read_input_tokens: z2.number().optional()
365
+ }).nullish(),
366
+ output_tokens_details: z2.looseObject({
367
+ reasoning_tokens: z2.number().optional()
368
+ }).nullish(),
369
+ tool_calls_details: z2.record(
370
+ z2.string(),
371
+ z2.looseObject({
372
+ invocation: z2.number().optional()
373
+ })
374
+ ).nullish(),
375
+ cost: perplexityCostSchema.nullish()
376
+ });
377
+ var perplexityAgentResponseSchema = z2.looseObject({
378
+ id: z2.string(),
379
+ created_at: z2.number(),
380
+ model: z2.string(),
381
+ object: z2.literal("response"),
382
+ output: z2.array(perplexityOutputItemSchema),
383
+ status: z2.string(),
384
+ incomplete_details: z2.looseObject({
385
+ reason: z2.string()
386
+ }).nullish(),
387
+ error: z2.looseObject({
388
+ code: z2.string().optional(),
389
+ message: z2.string(),
390
+ type: z2.string().optional()
391
+ }).nullish(),
392
+ usage: perplexityUsageSchema.nullish()
393
+ });
394
+ var perplexityAgentChunkSchema = z2.looseObject({
395
+ type: z2.string(),
396
+ sequence_number: z2.number().optional(),
397
+ response: perplexityAgentResponseSchema.optional(),
398
+ item: perplexityOutputItemSchema.optional(),
399
+ output_index: z2.number().optional(),
400
+ item_id: z2.string().optional(),
401
+ content_index: z2.number().optional(),
402
+ delta: z2.string().optional(),
403
+ text: z2.string().optional(),
404
+ thought: z2.string().optional(),
405
+ queries: z2.array(z2.string()).optional(),
406
+ urls: z2.array(z2.string()).optional(),
407
+ results: z2.array(perplexitySearchResultSchema).optional(),
408
+ contents: z2.array(perplexityFetchedContentSchema).optional(),
409
+ error: z2.looseObject({
410
+ code: z2.string().optional(),
411
+ message: z2.string(),
412
+ type: z2.string().optional()
413
+ }).optional()
414
+ });
415
+ var perplexityErrorSchema = z2.looseObject({
416
+ error: z2.union([
417
+ z2.string(),
418
+ z2.looseObject({
419
+ code: z2.union([z2.string(), z2.number()]).optional(),
420
+ message: z2.string().nullish(),
421
+ type: z2.string().nullish()
422
+ })
423
+ ]).optional(),
424
+ detail: z2.union([
425
+ z2.string(),
426
+ z2.array(
427
+ z2.looseObject({
428
+ msg: z2.string()
429
+ })
430
+ )
431
+ ]).optional(),
432
+ message: z2.string().optional()
433
+ });
434
+ function perplexityErrorToMessage(data) {
435
+ if (typeof data.error === "string") {
436
+ return data.error;
437
+ }
438
+ if (data.error != null) {
439
+ return data.error.message ?? data.error.type ?? "unknown error";
440
+ }
441
+ if (typeof data.detail === "string") {
442
+ return data.detail;
443
+ }
444
+ if (Array.isArray(data.detail)) {
445
+ return data.detail.map((detail) => detail.msg).join(", ");
446
+ }
447
+ return data.message ?? "unknown error";
448
+ }
449
+
450
+ // src/perplexity-language-model-options.ts
451
+ import { z as z3 } from "zod/v4";
452
+ var userLocationSchema = z3.looseObject({
453
+ latitude: z3.number().optional(),
454
+ longitude: z3.number().optional(),
455
+ country: z3.string().optional(),
456
+ city: z3.string().optional(),
457
+ region: z3.string().optional()
458
+ });
459
+ var webSearchFiltersSchema = z3.looseObject({
460
+ search_domain_filter: z3.array(z3.string()).optional(),
461
+ search_recency_filter: z3.enum(["hour", "day", "week", "month", "year"]).optional(),
462
+ search_after_date_filter: z3.string().optional(),
463
+ search_before_date_filter: z3.string().optional(),
464
+ last_updated_after_filter: z3.string().optional(),
465
+ last_updated_before_filter: z3.string().optional()
466
+ });
467
+ var webSearchToolSchema = z3.looseObject({
468
+ type: z3.literal("web_search"),
469
+ filters: webSearchFiltersSchema.optional(),
470
+ max_results: z3.number().int().positive().optional(),
471
+ max_tokens: z3.number().optional(),
472
+ max_tokens_per_page: z3.number().optional(),
473
+ search_context_size: z3.enum(["low", "medium", "high"]).optional(),
474
+ user_location: userLocationSchema.optional()
475
+ });
476
+ var nativeToolSchema = z3.union([
477
+ webSearchToolSchema,
478
+ z3.looseObject({
479
+ type: z3.literal("fetch_url"),
480
+ max_urls: z3.number().optional()
481
+ }),
482
+ z3.looseObject({ type: z3.literal("people_search") }),
483
+ z3.looseObject({ type: z3.literal("finance_search") }),
484
+ z3.looseObject({ type: z3.literal("sandbox") }),
485
+ z3.looseObject({
486
+ type: z3.literal("mcp"),
487
+ server_label: z3.string(),
488
+ server_url: z3.string(),
489
+ allowed_tools: z3.array(z3.string()).optional(),
490
+ authorization: z3.string().optional(),
491
+ defer_loading: z3.boolean().optional(),
492
+ headers: z3.record(z3.string(), z3.string()).optional()
493
+ }),
494
+ z3.looseObject({
495
+ type: z3.literal("connector"),
496
+ id: z3.string(),
497
+ server_label: z3.string(),
498
+ server_description: z3.string().optional(),
499
+ allowed_tools: z3.array(z3.string()).optional()
500
+ })
501
+ ]);
502
+ var perplexityLanguageModelOptions = z3.looseObject({
503
+ /** Top-level Agent API instructions. */
504
+ instructions: z3.string().optional(),
267
505
  /**
268
- * Restrict image results to specific file formats.
506
+ * Native Agent API tools. AI SDK function tools can also be supplied through
507
+ * the top-level `tools` option on `generateText` and `streamText`.
269
508
  */
270
- image_format_filter: z2.array(z2.string()).optional(),
509
+ tools: z3.array(nativeToolSchema).optional(),
510
+ /** A fallback model list for Agent API routing. */
511
+ models: z3.array(z3.string()).optional(),
512
+ /** Maximum number of agentic steps. */
513
+ max_steps: z3.number().int().positive().optional(),
514
+ /** Maximum number of native tool calls. */
515
+ max_tool_calls: z3.number().int().nonnegative().optional(),
516
+ /** Continue a conversation from an earlier Agent API response. */
517
+ previous_response_id: z3.string().optional(),
271
518
  /**
272
- * Additional media response configuration.
519
+ * Whether the response can be retrieved later. Setting this to false does
520
+ * not disable persistence or prevent previous_response_id continuations.
273
521
  */
274
- media_response: z2.looseObject({
275
- overrides: z2.looseObject({
276
- /**
277
- * If true, video results are included in the response.
278
- */
279
- return_videos: z2.boolean().optional()
280
- }).optional()
522
+ store: z3.boolean().optional(),
523
+ /** Preferred response language as an ISO 639-1 language code. */
524
+ language_preference: z3.string().optional(),
525
+ /** Agent API reasoning configuration. */
526
+ reasoning: z3.looseObject({
527
+ effort: z3.enum(["minimal", "low", "medium", "high", "xhigh"]).optional()
281
528
  }).optional(),
282
- /**
283
- * Controls the format of streaming events.
284
- */
285
- stream_mode: z2.enum(["full", "concise"]).optional(),
286
- /**
287
- * Controls how much effort the model spends on reasoning.
288
- */
289
- reasoning_effort: z2.enum(["minimal", "low", "medium", "high"]).optional(),
290
- /**
291
- * Preferred response language as an ISO 639-1 language code.
292
- */
293
- language_preference: z2.string().optional(),
294
- /**
295
- * Additional web search configuration.
296
- */
297
- web_search_options: z2.looseObject({
298
- /**
299
- * Controls the size of search context injected into the model.
300
- */
301
- search_context_size: z2.enum(["low", "medium", "high"]).optional(),
302
- /**
303
- * Controls whether to use fast search, pro search, or automatic routing.
304
- */
305
- search_type: z2.enum(["fast", "pro", "auto"]).optional(),
306
- /**
307
- * User location for search result personalization.
308
- */
309
- user_location: z2.looseObject({
310
- latitude: z2.number().optional(),
311
- longitude: z2.number().optional(),
312
- country: z2.string().optional(),
313
- city: z2.string().optional(),
314
- region: z2.string().optional()
315
- }).optional(),
316
- /**
317
- * If true, applies enhanced relevance filtering to image results.
318
- */
319
- image_results_enhanced_relevance: z2.boolean().optional()
320
- }).optional()
529
+ /** Agent API skill configuration. */
530
+ skills: z3.array(
531
+ z3.union([
532
+ z3.looseObject({
533
+ type: z3.literal("builtin"),
534
+ name: z3.enum([
535
+ "office",
536
+ "office/docx",
537
+ "office/pdf",
538
+ "office/pptx",
539
+ "office/xlsx"
540
+ ])
541
+ }),
542
+ z3.looseObject({
543
+ type: z3.literal("inline"),
544
+ name: z3.string(),
545
+ description: z3.string(),
546
+ instructions: z3.string()
547
+ })
548
+ ])
549
+ ).optional()
321
550
  });
322
551
 
552
+ // src/perplexity-prepare-tools.ts
553
+ function preparePerplexityTools({
554
+ tools,
555
+ toolChoice
556
+ }) {
557
+ const preparedTools = [];
558
+ const warnings = [];
559
+ for (const tool of tools ?? []) {
560
+ if (tool.type === "provider") {
561
+ warnings.push({
562
+ type: "unsupported",
563
+ feature: `provider-defined tool ${tool.name}`
564
+ });
565
+ continue;
566
+ }
567
+ preparedTools.push({
568
+ type: "function",
569
+ name: tool.name,
570
+ description: tool.description,
571
+ parameters: tool.inputSchema,
572
+ strict: tool.strict
573
+ });
574
+ }
575
+ if (toolChoice != null && toolChoice.type !== "auto") {
576
+ warnings.push({
577
+ type: "unsupported",
578
+ feature: "toolChoice",
579
+ details: "The Perplexity Agent API currently selects tools automatically."
580
+ });
581
+ }
582
+ return { tools: preparedTools, warnings };
583
+ }
584
+
323
585
  // src/perplexity-language-model.ts
586
+ var presetIds = /* @__PURE__ */ new Set([
587
+ "fast",
588
+ "low",
589
+ "medium",
590
+ "high",
591
+ "xhigh"
592
+ ]);
593
+ function getModelSelection(modelId) {
594
+ if (presetIds.has(modelId)) {
595
+ return { preset: modelId };
596
+ }
597
+ return { model: modelId };
598
+ }
599
+ function getResponseMetadata(response) {
600
+ return createLanguageModelResponseMetadata({
601
+ id: response.id,
602
+ model: response.model,
603
+ created: response.created_at
604
+ });
605
+ }
606
+ function getProviderMetadata(usage) {
607
+ const cost = usage?.cost;
608
+ const numSearchQueries = usage?.tool_calls_details ? Object.entries(usage.tool_calls_details).filter(([name]) => name.includes("search")).reduce((total, [, details]) => total + (details.invocation ?? 0), 0) : null;
609
+ return {
610
+ perplexity: {
611
+ usage: {
612
+ citationTokens: null,
613
+ numSearchQueries
614
+ },
615
+ images: null,
616
+ cost: cost == null ? null : {
617
+ inputTokensCost: cost.input_cost ?? null,
618
+ outputTokensCost: cost.output_cost ?? null,
619
+ requestCost: null,
620
+ totalCost: cost.total_cost ?? null,
621
+ currency: cost.currency ?? null,
622
+ cacheCreationCost: cost.cache_creation_cost ?? null,
623
+ cacheReadCost: cost.cache_read_cost ?? null,
624
+ toolCallsCost: cost.tool_calls_cost ?? null
625
+ },
626
+ toolCalls: usage?.tool_calls_details == null ? null : Object.fromEntries(
627
+ Object.entries(usage.tool_calls_details).map(
628
+ ([name, details]) => [
629
+ name,
630
+ { invocation: details.invocation ?? null }
631
+ ]
632
+ )
633
+ )
634
+ }
635
+ };
636
+ }
637
+ function createSource(result, generateId2) {
638
+ return {
639
+ type: "source",
640
+ sourceType: "url",
641
+ id: result.id == null ? generateId2() : String(result.id),
642
+ url: result.url,
643
+ title: result.title,
644
+ providerMetadata: {
645
+ perplexity: {
646
+ resultId: result.id ?? null,
647
+ snippet: result.snippet ?? null,
648
+ date: result.date ?? null,
649
+ lastUpdated: result.last_updated ?? null,
650
+ source: result.source ?? null
651
+ }
652
+ }
653
+ };
654
+ }
655
+ function hasSearchResultId(source) {
656
+ return typeof source.providerMetadata?.perplexity?.resultId === "number";
657
+ }
658
+ function getSearchResults(item) {
659
+ return item.type === "search_results" ? item.results ?? [] : [];
660
+ }
661
+ function getFetchedSources(item) {
662
+ return item.type === "fetch_url_results" ? item.contents ?? [] : [];
663
+ }
324
664
  var PerplexityLanguageModel = class _PerplexityLanguageModel {
325
665
  constructor(modelId, config) {
326
666
  this.specificationVersion = "v4";
327
667
  this.provider = "perplexity";
328
668
  this.supportedUrls = {
329
- // No URLs are supported.
669
+ "image/*": [/^https?:\/\/.*$/]
330
670
  };
331
671
  this.modelId = modelId;
332
672
  this.config = config;
@@ -352,97 +692,186 @@ var PerplexityLanguageModel = class _PerplexityLanguageModel {
352
692
  reasoning,
353
693
  responseFormat,
354
694
  seed,
355
- providerOptions
695
+ providerOptions,
696
+ tools,
697
+ toolChoice
356
698
  }) {
357
- var _a;
358
699
  const warnings = [];
359
- const perplexityOptions = (_a = await parseProviderOptions({
700
+ const perplexityOptions = await parseProviderOptions({
360
701
  provider: "perplexity",
361
702
  providerOptions,
362
703
  schema: perplexityLanguageModelOptions
363
- })) != null ? _a : {};
704
+ }) ?? {};
364
705
  if (topK != null) {
365
706
  warnings.push({ type: "unsupported", feature: "topK" });
366
707
  }
708
+ if (frequencyPenalty != null) {
709
+ warnings.push({ type: "unsupported", feature: "frequencyPenalty" });
710
+ }
711
+ if (presencePenalty != null) {
712
+ warnings.push({ type: "unsupported", feature: "presencePenalty" });
713
+ }
367
714
  if (stopSequences != null) {
368
715
  warnings.push({ type: "unsupported", feature: "stopSequences" });
369
716
  }
370
717
  if (seed != null) {
371
718
  warnings.push({ type: "unsupported", feature: "seed" });
372
719
  }
373
- if (isCustomReasoning(reasoning)) {
720
+ const { tools: nativeTools, ...agentOptions } = perplexityOptions;
721
+ const modelSelection = getModelSelection(this.modelId);
722
+ const { input, warnings: inputWarnings } = convertToPerplexityInput(prompt);
723
+ warnings.push(...inputWarnings);
724
+ const { tools: functionTools, warnings: toolWarnings } = preparePerplexityTools({ tools, toolChoice });
725
+ warnings.push(...toolWarnings);
726
+ const agentTools = [
727
+ ...nativeTools ?? [],
728
+ ...functionTools
729
+ ];
730
+ let reasoningConfig = agentOptions.reasoning;
731
+ if (reasoningConfig == null && isCustomReasoning(reasoning)) {
732
+ if (reasoning === "none") {
733
+ warnings.push({
734
+ type: "unsupported",
735
+ feature: 'reasoning "none"'
736
+ });
737
+ } else {
738
+ reasoningConfig = { effort: reasoning };
739
+ }
740
+ }
741
+ const body = {
742
+ ...agentOptions,
743
+ ...modelSelection,
744
+ input,
745
+ max_output_tokens: maxOutputTokens,
746
+ temperature,
747
+ top_p: topP,
748
+ reasoning: reasoningConfig,
749
+ response_format: responseFormat?.type === "json" && responseFormat.schema != null ? {
750
+ type: "json_schema",
751
+ json_schema: {
752
+ name: responseFormat.name ?? "response",
753
+ description: responseFormat.description,
754
+ schema: responseFormat.schema,
755
+ strict: true
756
+ }
757
+ } : void 0,
758
+ tools: agentTools.length > 0 ? agentTools : void 0
759
+ };
760
+ if (responseFormat?.type === "json" && responseFormat.schema == null) {
374
761
  warnings.push({
375
762
  type: "unsupported",
376
- feature: "reasoning",
377
- details: "This provider does not support reasoning configuration."
763
+ feature: "JSON response format without a schema"
378
764
  });
379
765
  }
380
- return {
381
- args: {
382
- // model id:
383
- model: this.modelId,
384
- // standardized settings:
385
- frequency_penalty: frequencyPenalty,
386
- max_tokens: maxOutputTokens,
387
- presence_penalty: presencePenalty,
388
- temperature,
389
- top_k: topK,
390
- top_p: topP,
391
- // response format:
392
- response_format: (responseFormat == null ? void 0 : responseFormat.type) === "json" ? {
393
- type: "json_schema",
394
- json_schema: { schema: responseFormat.schema }
395
- } : void 0,
396
- // provider extensions
397
- ...perplexityOptions,
398
- // messages:
399
- messages: convertToPerplexityMessages(prompt)
400
- },
401
- warnings
402
- };
766
+ return { args: body, warnings };
403
767
  }
404
768
  async doGenerate(options) {
405
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
406
769
  const { args: body, warnings } = await this.getArgs(options);
770
+ const url = `${this.config.baseURL}/v1/agent`;
407
771
  const {
408
772
  responseHeaders,
409
773
  value: response,
410
774
  rawValue: rawResponse
411
775
  } = await postJsonToApi({
412
- url: `${this.config.baseURL}/chat/completions`,
413
- headers: combineHeaders((_b = (_a = this.config).headers) == null ? void 0 : _b.call(_a), options.headers),
776
+ url,
777
+ headers: combineHeaders(this.config.headers?.(), options.headers),
414
778
  body,
415
779
  failedResponseHandler: createJsonErrorResponseHandler({
416
780
  errorSchema: perplexityErrorSchema,
417
- errorToMessage
781
+ errorToMessage: perplexityErrorToMessage
418
782
  }),
419
783
  successfulResponseHandler: createJsonResponseHandler(
420
- perplexityResponseSchema
784
+ perplexityAgentResponseSchema
421
785
  ),
422
786
  abortSignal: options.abortSignal,
423
787
  fetch: this.config.fetch
424
788
  });
425
- const choice = response.choices[0];
426
- const content = [];
427
- const text = choice.message.content;
428
- if (text.length > 0) {
429
- content.push({ type: "text", text });
789
+ if (response.error != null || response.status === "failed") {
790
+ throw new APICallError({
791
+ message: response.error?.message ?? "Perplexity response failed",
792
+ url,
793
+ requestBodyValues: body,
794
+ statusCode: 400,
795
+ responseHeaders,
796
+ responseBody: rawResponse,
797
+ isRetryable: false
798
+ });
430
799
  }
431
- if (response.citations != null) {
432
- for (const url of response.citations) {
800
+ const content = [];
801
+ const sourceIndexesByUrl = /* @__PURE__ */ new Map();
802
+ let hasFunctionCall = false;
803
+ const addSource = (source) => {
804
+ const existingIndex = sourceIndexesByUrl.get(source.url);
805
+ if (existingIndex == null) {
806
+ sourceIndexesByUrl.set(source.url, content.length);
807
+ content.push(source);
808
+ } else if (hasSearchResultId(source) && !hasSearchResultId(content[existingIndex])) {
809
+ content[existingIndex] = source;
810
+ }
811
+ };
812
+ for (const item of response.output) {
813
+ if (item.type === "message") {
814
+ for (const part of item.content ?? []) {
815
+ if (part.type === "output_text" && part.text != null) {
816
+ content.push({ type: "text", text: part.text });
817
+ }
818
+ for (const annotation of part.annotations ?? []) {
819
+ if (annotation.url != null) {
820
+ addSource({
821
+ type: "source",
822
+ sourceType: "url",
823
+ id: this.config.generateId(),
824
+ url: annotation.url,
825
+ title: annotation.title
826
+ });
827
+ }
828
+ }
829
+ }
830
+ } else if (item.type === "search_results") {
831
+ for (const result of getSearchResults(item)) {
832
+ addSource(createSource(result, this.config.generateId));
833
+ }
834
+ } else if (item.type === "fetch_url_results") {
835
+ for (const result of getFetchedSources(item)) {
836
+ addSource({
837
+ type: "source",
838
+ sourceType: "url",
839
+ id: this.config.generateId(),
840
+ url: result.url,
841
+ title: result.title,
842
+ providerMetadata: {
843
+ perplexity: { snippet: result.snippet ?? null }
844
+ }
845
+ });
846
+ }
847
+ } else if (item.type === "function_call" && item.call_id != null && item.name != null && item.arguments != null) {
848
+ hasFunctionCall = true;
433
849
  content.push({
434
- type: "source",
435
- sourceType: "url",
436
- id: this.config.generateId(),
437
- url
850
+ type: "tool-call",
851
+ toolCallId: item.call_id,
852
+ toolName: item.name,
853
+ input: item.arguments,
854
+ providerMetadata: {
855
+ perplexity: {
856
+ itemId: item.id ?? null,
857
+ ...item.thought_signature != null && {
858
+ thoughtSignature: item.thought_signature
859
+ }
860
+ }
861
+ }
438
862
  });
439
863
  }
440
864
  }
865
+ const finishReason = response.incomplete_details?.reason ?? response.status;
441
866
  return {
442
867
  content,
443
868
  finishReason: {
444
- unified: mapPerplexityFinishReason(choice.finish_reason),
445
- raw: (_c = choice.finish_reason) != null ? _c : void 0
869
+ unified: mapPerplexityFinishReason({
870
+ status: response.status,
871
+ incompleteReason: response.incomplete_details?.reason,
872
+ hasFunctionCall
873
+ }),
874
+ raw: finishReason
446
875
  },
447
876
  usage: convertPerplexityUsage(response.usage),
448
877
  request: { body },
@@ -452,42 +881,22 @@ var PerplexityLanguageModel = class _PerplexityLanguageModel {
452
881
  body: rawResponse
453
882
  },
454
883
  warnings,
455
- providerMetadata: {
456
- perplexity: {
457
- images: (_e = (_d = response.images) == null ? void 0 : _d.map((image) => ({
458
- imageUrl: image.image_url,
459
- originUrl: image.origin_url,
460
- height: image.height,
461
- width: image.width
462
- }))) != null ? _e : null,
463
- usage: {
464
- citationTokens: (_g = (_f = response.usage) == null ? void 0 : _f.citation_tokens) != null ? _g : null,
465
- numSearchQueries: (_i = (_h = response.usage) == null ? void 0 : _h.num_search_queries) != null ? _i : null
466
- },
467
- cost: ((_j = response.usage) == null ? void 0 : _j.cost) ? {
468
- inputTokensCost: (_k = response.usage.cost.input_tokens_cost) != null ? _k : null,
469
- outputTokensCost: (_l = response.usage.cost.output_tokens_cost) != null ? _l : null,
470
- requestCost: (_m = response.usage.cost.request_cost) != null ? _m : null,
471
- totalCost: (_n = response.usage.cost.total_cost) != null ? _n : null
472
- } : null
473
- }
474
- }
884
+ providerMetadata: getProviderMetadata(response.usage)
475
885
  };
476
886
  }
477
887
  async doStream(options) {
478
- var _a, _b;
479
888
  const { args, warnings } = await this.getArgs(options);
480
889
  const body = { ...args, stream: true };
481
890
  const { responseHeaders, value: response } = await postJsonToApi({
482
- url: `${this.config.baseURL}/chat/completions`,
483
- headers: combineHeaders((_b = (_a = this.config).headers) == null ? void 0 : _b.call(_a), options.headers),
891
+ url: `${this.config.baseURL}/v1/agent`,
892
+ headers: combineHeaders(this.config.headers?.(), options.headers),
484
893
  body,
485
894
  failedResponseHandler: createJsonErrorResponseHandler({
486
895
  errorSchema: perplexityErrorSchema,
487
- errorToMessage
896
+ errorToMessage: perplexityErrorToMessage
488
897
  }),
489
898
  successfulResponseHandler: createEventSourceResponseHandler(
490
- perplexityChunkSchema
899
+ perplexityAgentChunkSchema
491
900
  ),
492
901
  abortSignal: options.abortSignal,
493
902
  fetch: this.config.fetch
@@ -496,20 +905,15 @@ var PerplexityLanguageModel = class _PerplexityLanguageModel {
496
905
  unified: "other",
497
906
  raw: void 0
498
907
  };
499
- let usage = void 0;
500
- const providerMetadata = {
501
- perplexity: {
502
- usage: {
503
- citationTokens: null,
504
- numSearchQueries: null
505
- },
506
- cost: null,
507
- images: null
508
- }
509
- };
510
- let isFirstChunk = true;
511
- let isActive = false;
512
- const self = this;
908
+ let usage;
909
+ let hasFunctionCall = false;
910
+ let hasResponseMetadata = false;
911
+ let activeReasoningId;
912
+ const textStates = /* @__PURE__ */ new Map();
913
+ const emittedSourceUrls = /* @__PURE__ */ new Set();
914
+ const pendingSourcesByUrl = /* @__PURE__ */ new Map();
915
+ const seenFunctionCalls = /* @__PURE__ */ new Set();
916
+ const generateId2 = this.config.generateId;
513
917
  return {
514
918
  stream: response.pipeThrough(
515
919
  new TransformStream({
@@ -517,84 +921,303 @@ var PerplexityLanguageModel = class _PerplexityLanguageModel {
517
921
  controller.enqueue({ type: "stream-start", warnings });
518
922
  },
519
923
  transform(chunk, controller) {
520
- var _a2, _b2, _c, _d, _e, _f, _g;
521
924
  if (options.includeRawChunks) {
522
925
  controller.enqueue({ type: "raw", rawValue: chunk.rawValue });
523
926
  }
524
927
  if (!chunk.success) {
928
+ finishReason = { unified: "error", raw: void 0 };
525
929
  controller.enqueue({ type: "error", error: chunk.error });
526
930
  return;
527
931
  }
528
932
  const value = chunk.value;
529
- if (isFirstChunk) {
933
+ const getTextId = (itemId, outputIndex, contentIndex = 0) => {
934
+ const id = itemId ?? String(outputIndex ?? "text");
935
+ return contentIndex === 0 ? id : `${id}:${contentIndex}`;
936
+ };
937
+ const emitTextDelta = (id, delta) => {
938
+ let state = textStates.get(id);
939
+ if (state?.ended) {
940
+ return;
941
+ }
942
+ if (state == null) {
943
+ state = { text: "", ended: false };
944
+ textStates.set(id, state);
945
+ controller.enqueue({ type: "text-start", id });
946
+ }
947
+ state.text += delta;
948
+ controller.enqueue({ type: "text-delta", id, delta });
949
+ };
950
+ const finishText = (id, text) => {
951
+ const state = textStates.get(id);
952
+ if (state?.ended) {
953
+ return;
954
+ }
955
+ const emittedText = state?.text ?? "";
956
+ if (text != null && text.startsWith(emittedText) && text.length > emittedText.length) {
957
+ emitTextDelta(id, text.slice(emittedText.length));
958
+ }
959
+ const finalState = textStates.get(id);
960
+ if (finalState != null) {
961
+ finalState.ended = true;
962
+ controller.enqueue({ type: "text-end", id });
963
+ }
964
+ };
965
+ const finishOutputText = (item, outputIndex) => {
966
+ if (item.type === "message") {
967
+ for (const [contentIndex, part] of (item.content ?? []).entries()) {
968
+ if (part.type === "output_text") {
969
+ finishText(
970
+ getTextId(item.id, outputIndex, contentIndex),
971
+ part.text
972
+ );
973
+ }
974
+ }
975
+ }
976
+ };
977
+ const emitSource = (source) => {
978
+ if (emittedSourceUrls.has(source.url)) {
979
+ return;
980
+ }
981
+ if (hasSearchResultId(source)) {
982
+ pendingSourcesByUrl.delete(source.url);
983
+ emittedSourceUrls.add(source.url);
984
+ controller.enqueue(source);
985
+ } else if (!pendingSourcesByUrl.has(source.url)) {
986
+ pendingSourcesByUrl.set(source.url, source);
987
+ }
988
+ };
989
+ const emitReasoningThought = (thought) => {
990
+ if (activeReasoningId != null && thought != null) {
991
+ controller.enqueue({
992
+ type: "reasoning-delta",
993
+ id: activeReasoningId,
994
+ delta: thought
995
+ });
996
+ }
997
+ };
998
+ const emitFunctionCall = (item) => {
999
+ if (item.type !== "function_call" || item.call_id == null || item.name == null || item.arguments == null || seenFunctionCalls.has(item.call_id)) {
1000
+ return;
1001
+ }
1002
+ seenFunctionCalls.add(item.call_id);
1003
+ hasFunctionCall = true;
530
1004
  controller.enqueue({
531
- type: "response-metadata",
532
- ...getResponseMetadata(value)
1005
+ type: "tool-input-start",
1006
+ id: item.call_id,
1007
+ toolName: item.name
533
1008
  });
534
- (_a2 = value.citations) == null ? void 0 : _a2.forEach((url) => {
535
- controller.enqueue({
1009
+ controller.enqueue({
1010
+ type: "tool-input-delta",
1011
+ id: item.call_id,
1012
+ delta: item.arguments
1013
+ });
1014
+ controller.enqueue({ type: "tool-input-end", id: item.call_id });
1015
+ controller.enqueue({
1016
+ type: "tool-call",
1017
+ toolCallId: item.call_id,
1018
+ toolName: item.name,
1019
+ input: item.arguments,
1020
+ providerMetadata: {
1021
+ perplexity: {
1022
+ itemId: item.id ?? null,
1023
+ ...item.thought_signature != null && {
1024
+ thoughtSignature: item.thought_signature
1025
+ }
1026
+ }
1027
+ }
1028
+ });
1029
+ };
1030
+ const emitOutputSources = (item) => {
1031
+ if (item.type === "message") {
1032
+ for (const part of item.content ?? []) {
1033
+ for (const annotation of part.annotations ?? []) {
1034
+ if (annotation.url != null) {
1035
+ emitSource({
1036
+ type: "source",
1037
+ sourceType: "url",
1038
+ id: generateId2(),
1039
+ url: annotation.url,
1040
+ title: annotation.title
1041
+ });
1042
+ }
1043
+ }
1044
+ }
1045
+ }
1046
+ for (const result of getSearchResults(item)) {
1047
+ emitSource(createSource(result, generateId2));
1048
+ }
1049
+ for (const result of getFetchedSources(item)) {
1050
+ emitSource({
536
1051
  type: "source",
537
1052
  sourceType: "url",
538
- id: self.config.generateId(),
539
- url
1053
+ id: generateId2(),
1054
+ url: result.url,
1055
+ title: result.title,
1056
+ providerMetadata: {
1057
+ perplexity: { snippet: result.snippet ?? null }
1058
+ }
540
1059
  });
541
- });
542
- isFirstChunk = false;
543
- }
544
- if (value.usage != null) {
545
- usage = value.usage;
546
- providerMetadata.perplexity.usage = {
547
- citationTokens: (_b2 = value.usage.citation_tokens) != null ? _b2 : null,
548
- numSearchQueries: (_c = value.usage.num_search_queries) != null ? _c : null
549
- };
550
- providerMetadata.perplexity.cost = value.usage.cost ? {
551
- inputTokensCost: (_d = value.usage.cost.input_tokens_cost) != null ? _d : null,
552
- outputTokensCost: (_e = value.usage.cost.output_tokens_cost) != null ? _e : null,
553
- requestCost: (_f = value.usage.cost.request_cost) != null ? _f : null,
554
- totalCost: (_g = value.usage.cost.total_cost) != null ? _g : null
555
- } : null;
556
- }
557
- if (value.images != null) {
558
- providerMetadata.perplexity.images = value.images.map((image) => ({
559
- imageUrl: image.image_url,
560
- originUrl: image.origin_url,
561
- height: image.height,
562
- width: image.width
563
- }));
564
- }
565
- const choice = value.choices[0];
566
- if ((choice == null ? void 0 : choice.finish_reason) != null) {
567
- finishReason = {
568
- unified: mapPerplexityFinishReason(choice.finish_reason),
569
- raw: choice.finish_reason
570
- };
1060
+ }
1061
+ };
1062
+ switch (value.type) {
1063
+ case "response.created":
1064
+ case "response.in_progress": {
1065
+ if (!hasResponseMetadata && value.response != null) {
1066
+ controller.enqueue({
1067
+ type: "response-metadata",
1068
+ ...getResponseMetadata(value.response)
1069
+ });
1070
+ hasResponseMetadata = true;
1071
+ }
1072
+ break;
1073
+ }
1074
+ case "response.output_text.delta": {
1075
+ if (value.delta != null) {
1076
+ emitTextDelta(
1077
+ getTextId(
1078
+ value.item_id,
1079
+ value.output_index,
1080
+ value.content_index
1081
+ ),
1082
+ value.delta
1083
+ );
1084
+ }
1085
+ break;
1086
+ }
1087
+ case "response.output_text.done": {
1088
+ finishText(
1089
+ getTextId(
1090
+ value.item_id,
1091
+ value.output_index,
1092
+ value.content_index
1093
+ ),
1094
+ value.text
1095
+ );
1096
+ break;
1097
+ }
1098
+ case "response.reasoning.started": {
1099
+ if (activeReasoningId != null) {
1100
+ controller.enqueue({
1101
+ type: "reasoning-end",
1102
+ id: activeReasoningId
1103
+ });
1104
+ }
1105
+ activeReasoningId = `reasoning-${value.sequence_number ?? generateId2()}`;
1106
+ controller.enqueue({
1107
+ type: "reasoning-start",
1108
+ id: activeReasoningId
1109
+ });
1110
+ emitReasoningThought(value.thought);
1111
+ break;
1112
+ }
1113
+ case "response.reasoning.search_queries":
1114
+ case "response.reasoning.fetch_url_queries": {
1115
+ emitReasoningThought(value.thought);
1116
+ break;
1117
+ }
1118
+ case "response.reasoning.search_results": {
1119
+ emitReasoningThought(value.thought);
1120
+ for (const result of value.results ?? []) {
1121
+ emitSource(createSource(result, generateId2));
1122
+ }
1123
+ break;
1124
+ }
1125
+ case "response.reasoning.fetch_url_results": {
1126
+ emitReasoningThought(value.thought);
1127
+ for (const result of value.contents ?? []) {
1128
+ emitSource({
1129
+ type: "source",
1130
+ sourceType: "url",
1131
+ id: generateId2(),
1132
+ url: result.url,
1133
+ title: result.title,
1134
+ providerMetadata: {
1135
+ perplexity: { snippet: result.snippet ?? null }
1136
+ }
1137
+ });
1138
+ }
1139
+ break;
1140
+ }
1141
+ case "response.reasoning.stopped": {
1142
+ emitReasoningThought(value.thought);
1143
+ if (activeReasoningId != null) {
1144
+ controller.enqueue({
1145
+ type: "reasoning-end",
1146
+ id: activeReasoningId
1147
+ });
1148
+ activeReasoningId = void 0;
1149
+ }
1150
+ break;
1151
+ }
1152
+ case "response.output_item.done": {
1153
+ if (value.item != null) {
1154
+ finishOutputText(value.item, value.output_index);
1155
+ emitOutputSources(value.item);
1156
+ emitFunctionCall(value.item);
1157
+ }
1158
+ break;
1159
+ }
1160
+ case "response.completed":
1161
+ case "response.incomplete": {
1162
+ if (value.response != null) {
1163
+ if (!hasResponseMetadata) {
1164
+ controller.enqueue({
1165
+ type: "response-metadata",
1166
+ ...getResponseMetadata(value.response)
1167
+ });
1168
+ hasResponseMetadata = true;
1169
+ }
1170
+ for (const [
1171
+ outputIndex,
1172
+ item
1173
+ ] of value.response.output.entries()) {
1174
+ finishOutputText(item, outputIndex);
1175
+ emitOutputSources(item);
1176
+ emitFunctionCall(item);
1177
+ }
1178
+ usage = value.response.usage ?? void 0;
1179
+ const rawFinishReason = value.response.incomplete_details?.reason ?? value.response.status;
1180
+ finishReason = {
1181
+ unified: mapPerplexityFinishReason({
1182
+ status: value.response.status,
1183
+ incompleteReason: value.response.incomplete_details?.reason,
1184
+ hasFunctionCall
1185
+ }),
1186
+ raw: rawFinishReason
1187
+ };
1188
+ }
1189
+ break;
1190
+ }
1191
+ case "response.failed": {
1192
+ finishReason = { unified: "error", raw: "failed" };
1193
+ controller.enqueue({
1194
+ type: "error",
1195
+ error: value.error ?? new Error("Perplexity response failed")
1196
+ });
1197
+ break;
1198
+ }
571
1199
  }
572
- if ((choice == null ? void 0 : choice.delta) == null) {
573
- return;
1200
+ },
1201
+ flush(controller) {
1202
+ for (const source of pendingSourcesByUrl.values()) {
1203
+ controller.enqueue(source);
574
1204
  }
575
- const delta = choice.delta;
576
- const textContent = delta.content;
577
- if (textContent != null) {
578
- if (!isActive) {
579
- controller.enqueue({ type: "text-start", id: "0" });
580
- isActive = true;
581
- }
1205
+ if (activeReasoningId != null) {
582
1206
  controller.enqueue({
583
- type: "text-delta",
584
- id: "0",
585
- delta: textContent
1207
+ type: "reasoning-end",
1208
+ id: activeReasoningId
586
1209
  });
587
1210
  }
588
- },
589
- flush(controller) {
590
- if (isActive) {
591
- controller.enqueue({ type: "text-end", id: "0" });
1211
+ for (const [id, state] of textStates) {
1212
+ if (!state.ended) {
1213
+ controller.enqueue({ type: "text-end", id });
1214
+ }
592
1215
  }
593
1216
  controller.enqueue({
594
1217
  type: "finish",
595
1218
  finishReason,
596
1219
  usage: convertPerplexityUsage(usage),
597
- providerMetadata
1220
+ providerMetadata: getProviderMetadata(usage)
598
1221
  });
599
1222
  }
600
1223
  })
@@ -604,76 +1227,6 @@ var PerplexityLanguageModel = class _PerplexityLanguageModel {
604
1227
  };
605
1228
  }
606
1229
  };
607
- var perplexityCostSchema = z3.object({
608
- input_tokens_cost: z3.number().nullish(),
609
- output_tokens_cost: z3.number().nullish(),
610
- reasoning_tokens_cost: z3.number().nullish(),
611
- request_cost: z3.number().nullish(),
612
- citation_tokens_cost: z3.number().nullish(),
613
- search_queries_cost: z3.number().nullish(),
614
- total_cost: z3.number().nullish()
615
- }).catchall(z3.json());
616
- var perplexityUsageSchema = z3.object({
617
- prompt_tokens: z3.number(),
618
- completion_tokens: z3.number(),
619
- total_tokens: z3.number().nullish(),
620
- search_context_size: z3.enum(["low", "medium", "high"]).nullish(),
621
- citation_tokens: z3.number().nullish(),
622
- num_search_queries: z3.number().nullish(),
623
- reasoning_tokens: z3.number().nullish(),
624
- cost: perplexityCostSchema.nullish()
625
- }).catchall(z3.json());
626
- var perplexityImageSchema = z3.object({
627
- image_url: z3.string(),
628
- origin_url: z3.string(),
629
- height: z3.number(),
630
- width: z3.number()
631
- });
632
- var perplexityResponseSchema = z3.object({
633
- id: z3.string(),
634
- created: z3.number(),
635
- model: z3.string(),
636
- choices: z3.array(
637
- z3.object({
638
- message: z3.object({
639
- role: z3.literal("assistant"),
640
- content: z3.string()
641
- }),
642
- finish_reason: z3.string().nullish()
643
- })
644
- ),
645
- citations: z3.array(z3.string()).nullish(),
646
- images: z3.array(perplexityImageSchema).nullish(),
647
- usage: perplexityUsageSchema.nullish()
648
- });
649
- var perplexityChunkSchema = z3.object({
650
- id: z3.string(),
651
- created: z3.number(),
652
- model: z3.string(),
653
- choices: z3.array(
654
- z3.object({
655
- delta: z3.object({
656
- role: z3.literal("assistant").optional(),
657
- content: z3.string().nullish()
658
- }),
659
- finish_reason: z3.string().nullish()
660
- })
661
- ),
662
- citations: z3.array(z3.string()).nullish(),
663
- images: z3.array(perplexityImageSchema).nullish(),
664
- usage: perplexityUsageSchema.nullish()
665
- });
666
- var perplexityErrorSchema = z3.object({
667
- error: z3.object({
668
- code: z3.number(),
669
- message: z3.string().nullish(),
670
- type: z3.string().nullish()
671
- })
672
- });
673
- var errorToMessage = (data) => {
674
- var _a, _b;
675
- return (_b = (_a = data.error.message) != null ? _a : data.error.type) != null ? _b : "unknown error";
676
- };
677
1230
 
678
1231
  // src/perplexity-embedding-model.ts
679
1232
  var PerplexityEmbeddingModel = class _PerplexityEmbeddingModel {
@@ -703,7 +1256,6 @@ var PerplexityEmbeddingModel = class _PerplexityEmbeddingModel {
703
1256
  headers,
704
1257
  providerOptions
705
1258
  }) {
706
- var _a, _b, _c, _d, _e, _f;
707
1259
  if (values.length > this.maxEmbeddingsPerCall) {
708
1260
  throw new TooManyEmbeddingValuesForCallError({
709
1261
  provider: this.provider,
@@ -712,12 +1264,12 @@ var PerplexityEmbeddingModel = class _PerplexityEmbeddingModel {
712
1264
  values
713
1265
  });
714
1266
  }
715
- const perplexityOptions = (_a = await parseProviderOptions2({
1267
+ const perplexityOptions = await parseProviderOptions2({
716
1268
  provider: "perplexity",
717
1269
  providerOptions,
718
1270
  schema: perplexityEmbeddingModelOptions
719
- })) != null ? _a : {};
720
- const encodingFormat = (_b = perplexityOptions.encodingFormat) != null ? _b : "base64_int8";
1271
+ }) ?? {};
1272
+ const encodingFormat = perplexityOptions.encodingFormat ?? "base64_int8";
721
1273
  const {
722
1274
  responseHeaders,
723
1275
  value: response,
@@ -733,10 +1285,7 @@ var PerplexityEmbeddingModel = class _PerplexityEmbeddingModel {
733
1285
  },
734
1286
  failedResponseHandler: createJsonErrorResponseHandler2({
735
1287
  errorSchema: perplexityErrorSchema,
736
- errorToMessage: (data) => {
737
- var _a2;
738
- return (_a2 = data.error.message) != null ? _a2 : "Unknown error";
739
- }
1288
+ errorToMessage: perplexityErrorToMessage
740
1289
  }),
741
1290
  successfulResponseHandler: createJsonResponseHandler2(
742
1291
  perplexityEmbeddingResponseSchema
@@ -744,7 +1293,7 @@ var PerplexityEmbeddingModel = class _PerplexityEmbeddingModel {
744
1293
  abortSignal,
745
1294
  fetch: this.config.fetch
746
1295
  });
747
- const cost = (_c = response.usage) == null ? void 0 : _c.cost;
1296
+ const cost = response.usage?.cost;
748
1297
  return {
749
1298
  embeddings: response.data.map(
750
1299
  (item) => decodeEmbedding(item.embedding, encodingFormat)
@@ -753,9 +1302,9 @@ var PerplexityEmbeddingModel = class _PerplexityEmbeddingModel {
753
1302
  providerMetadata: cost ? {
754
1303
  perplexity: {
755
1304
  cost: {
756
- inputCost: (_d = cost.input_cost) != null ? _d : null,
757
- totalCost: (_e = cost.total_cost) != null ? _e : null,
758
- currency: (_f = cost.currency) != null ? _f : null
1305
+ inputCost: cost.input_cost ?? null,
1306
+ totalCost: cost.total_cost ?? null,
1307
+ currency: cost.currency ?? null
759
1308
  }
760
1309
  }
761
1310
  } : void 0,
@@ -789,11 +1338,10 @@ var perplexityEmbeddingResponseSchema = z4.object({
789
1338
  });
790
1339
 
791
1340
  // src/version.ts
792
- var VERSION = true ? "4.0.50" : "0.0.0-test";
1341
+ var VERSION = true ? "5.0.0" : "0.0.0-test";
793
1342
 
794
1343
  // src/perplexity-provider.ts
795
1344
  function createPerplexity(options = {}) {
796
- var _a;
797
1345
  const getHeaders = () => withUserAgentSuffix(
798
1346
  {
799
1347
  Authorization: `Bearer ${loadApiKey({
@@ -806,7 +1354,7 @@ function createPerplexity(options = {}) {
806
1354
  `ai-sdk/perplexity/${VERSION}`
807
1355
  );
808
1356
  const baseURL = withoutTrailingSlash(
809
- (_a = options.baseURL) != null ? _a : "https://api.perplexity.ai"
1357
+ options.baseURL ?? "https://api.perplexity.ai"
810
1358
  );
811
1359
  const createLanguageModel = (modelId) => {
812
1360
  return new PerplexityLanguageModel(modelId, {