Skip to content

Commit a12f234

Browse files
authored
added perplexity tool (#129)
1 parent df0b2d2 commit a12f234

File tree

6 files changed

+291
-0
lines changed

6 files changed

+291
-0
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { PerplexityIcon } from '@/components/icons'
2+
import { ToolResponse } from '@/tools/types'
3+
import { BlockConfig } from '../types'
4+
5+
interface PerplexityChatResponse extends ToolResponse {
6+
output: {
7+
content: string
8+
model: string
9+
usage: {
10+
prompt_tokens: number
11+
completion_tokens: number
12+
total_tokens: number
13+
}
14+
}
15+
}
16+
17+
export const PerplexityBlock: BlockConfig<PerplexityChatResponse> = {
18+
type: 'perplexity',
19+
name: 'Perplexity',
20+
description: 'Use Perplexity AI chat models',
21+
longDescription:
22+
'Generate completions using Perplexity AI models with real-time knowledge and search capabilities. Create responses, answer questions, and generate content with customizable parameters.',
23+
category: 'tools',
24+
bgColor: '#20808D', // Perplexity turquoise color
25+
icon: PerplexityIcon,
26+
subBlocks: [
27+
{
28+
id: 'system',
29+
title: 'System Prompt',
30+
type: 'long-input',
31+
layout: 'full',
32+
placeholder: 'Optional system prompt to guide the model behavior...',
33+
},
34+
{
35+
id: 'prompt',
36+
title: 'User Prompt',
37+
type: 'long-input',
38+
layout: 'full',
39+
placeholder: 'Enter your prompt here...',
40+
},
41+
{
42+
id: 'model',
43+
title: 'Model',
44+
type: 'dropdown',
45+
layout: 'half',
46+
options: [
47+
{ label: 'Sonar', id: 'sonar' },
48+
{ label: 'Mistral', id: 'mistral' },
49+
{ label: 'Claude-3-Opus', id: 'claude-3-opus' },
50+
{ label: 'Claude-3-Sonnet', id: 'claude-3-sonnet' },
51+
{ label: 'Command-R', id: 'command-r' },
52+
{ label: 'GPT-4o', id: 'gpt-4o' },
53+
],
54+
value: () => 'sonar',
55+
},
56+
{
57+
id: 'temperature',
58+
title: 'Temperature',
59+
type: 'slider',
60+
layout: 'half',
61+
min: 0,
62+
max: 1,
63+
value: () => '0.7',
64+
},
65+
{
66+
id: 'max_tokens',
67+
title: 'Max Tokens',
68+
type: 'short-input',
69+
layout: 'half',
70+
placeholder: 'Maximum number of tokens',
71+
},
72+
{
73+
id: 'apiKey',
74+
title: 'API Key',
75+
type: 'short-input',
76+
layout: 'full',
77+
placeholder: 'Enter your Perplexity API key',
78+
password: true,
79+
},
80+
],
81+
tools: {
82+
access: ['perplexity_chat'],
83+
config: {
84+
tool: () => 'perplexity_chat',
85+
params: (params) => {
86+
const toolParams = {
87+
apiKey: params.apiKey,
88+
model: params.model,
89+
prompt: params.prompt,
90+
system: params.system,
91+
max_tokens: params.max_tokens ? parseInt(params.max_tokens) : undefined,
92+
temperature: params.temperature ? parseFloat(params.temperature) : undefined,
93+
}
94+
95+
return toolParams
96+
},
97+
},
98+
},
99+
inputs: {
100+
prompt: { type: 'string', required: true },
101+
system: { type: 'string', required: false },
102+
model: { type: 'string', required: true },
103+
max_tokens: { type: 'string', required: false },
104+
temperature: { type: 'string', required: false },
105+
apiKey: { type: 'string', required: true },
106+
},
107+
outputs: {
108+
response: {
109+
type: {
110+
content: 'string',
111+
model: 'string',
112+
usage: 'json',
113+
},
114+
},
115+
},
116+
}

sim/app/blocks/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { GuestyBlock } from './blocks/guesty'
1414
import { JinaBlock } from './blocks/jina'
1515
import { NotionBlock } from './blocks/notion'
1616
import { OpenAIBlock } from './blocks/openai'
17+
import { PerplexityBlock } from './blocks/perplexity'
1718
import { PineconeBlock } from './blocks/pinecone'
1819
import { RedditBlock } from './blocks/reddit'
1920
import { RouterBlock } from './blocks/router'
@@ -61,6 +62,7 @@ export {
6162
GoogleDocsBlock,
6263
WhatsAppBlock,
6364
GoogleSheetsBlock,
65+
PerplexityBlock,
6466
}
6567

6668
// Registry of all block configurations, alphabetically sorted
@@ -81,6 +83,7 @@ const blocks: Record<string, BlockConfig> = {
8183
jina: JinaBlock,
8284
notion: NotionBlock,
8385
openai: OpenAIBlock,
86+
perplexity: PerplexityBlock,
8487
pinecone: PineconeBlock,
8588
reddit: RedditBlock,
8689
router: RouterBlock,

sim/app/tools/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { contactsTool as hubspotContacts } from './hubspot/contacts'
1414
import { readUrlTool } from './jina/reader'
1515
import { notionReadTool, notionWriteTool } from './notion'
1616
import { embeddingsTool as openAIEmbeddings } from './openai/embeddings'
17+
import { perplexityChatTool } from './perplexity'
1718
import {
1819
pineconeFetchTool,
1920
pineconeGenerateEmbeddingsTool,
@@ -90,6 +91,7 @@ export const tools: Record<string, ToolConfig> = {
9091
google_sheets_update: sheetsUpdateTool,
9192
guesty_reservation: guestyReservationTool,
9293
guesty_guest: guestyGuestTool,
94+
perplexity_chat: perplexityChatTool,
9395
}
9496

9597
// Get a tool by its ID

sim/app/tools/perplexity/chat.ts

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import { ToolConfig } from '../types'
2+
import { PerplexityChatParams, PerplexityChatResponse } from './types'
3+
4+
export const chatTool: ToolConfig<PerplexityChatParams, PerplexityChatResponse> = {
5+
id: 'perplexity_chat',
6+
name: 'Perplexity Chat',
7+
description: 'Generate completions using Perplexity AI chat models',
8+
version: '1.0',
9+
10+
params: {
11+
apiKey: {
12+
type: 'string',
13+
required: true,
14+
requiredForToolCall: true,
15+
description: 'Perplexity API key',
16+
},
17+
model: {
18+
type: 'string',
19+
required: true,
20+
description: 'Model to use for chat completions (e.g., sonar, mistral)',
21+
},
22+
messages: {
23+
type: 'array',
24+
required: true,
25+
description: 'Array of message objects with role and content',
26+
},
27+
max_tokens: {
28+
type: 'number',
29+
required: false,
30+
description: 'Maximum number of tokens to generate',
31+
},
32+
temperature: {
33+
type: 'number',
34+
required: false,
35+
description: 'Sampling temperature between 0 and 1',
36+
},
37+
},
38+
39+
request: {
40+
method: 'POST',
41+
url: () => 'https://api.perplexity.ai/chat/completions',
42+
headers: (params) => ({
43+
Authorization: `Bearer ${params.apiKey}`,
44+
'Content-Type': 'application/json',
45+
}),
46+
body: (params) => {
47+
let messages = params.messages
48+
49+
if (!messages && (params.prompt || params.system)) {
50+
messages = []
51+
52+
// Add system message if provided
53+
if (params.system && typeof params.system === 'string' && params.system.trim() !== '') {
54+
messages.push({
55+
role: 'system',
56+
content: params.system,
57+
})
58+
}
59+
60+
// Add user message
61+
if (params.prompt && typeof params.prompt === 'string' && params.prompt.trim() !== '') {
62+
messages.push({
63+
role: 'user',
64+
content: params.prompt,
65+
})
66+
}
67+
}
68+
69+
// Validate that each message has role and content
70+
for (const msg of messages!) {
71+
if (!msg.role || !msg.content) {
72+
throw new Error('Each message must have role and content properties')
73+
}
74+
}
75+
76+
const body: Record<string, any> = {
77+
model: params.model,
78+
messages: messages,
79+
}
80+
81+
if (params.max_tokens !== undefined) {
82+
body.max_tokens = params.max_tokens
83+
}
84+
85+
if (params.temperature !== undefined) {
86+
body.temperature = params.temperature
87+
}
88+
89+
return body
90+
},
91+
},
92+
93+
transformResponse: async (response, params) => {
94+
try {
95+
// Check if the response was successful
96+
if (!response.ok) {
97+
const errorData = await response.json().catch(() => null)
98+
console.error('Perplexity API error:', {
99+
status: response.status,
100+
statusText: response.statusText,
101+
errorData,
102+
})
103+
104+
const errorMessage = errorData
105+
? JSON.stringify(errorData)
106+
: `API error: ${response.status} ${response.statusText}`
107+
108+
throw new Error(errorMessage)
109+
}
110+
111+
const data = await response.json()
112+
113+
// Validate response structure
114+
if (!data.choices || !data.choices[0] || !data.choices[0].message) {
115+
console.error('Invalid Perplexity response format:', data)
116+
throw new Error('Invalid response format from Perplexity API')
117+
}
118+
119+
return {
120+
success: true,
121+
output: {
122+
content: data.choices[0].message.content,
123+
model: data.model,
124+
usage: {
125+
prompt_tokens: data.usage.prompt_tokens,
126+
completion_tokens: data.usage.completion_tokens,
127+
total_tokens: data.usage.total_tokens,
128+
},
129+
},
130+
}
131+
} catch (error: any) {
132+
console.error('Failed to process Perplexity response:', error)
133+
throw error
134+
}
135+
},
136+
137+
transformError: (error) => `Perplexity chat completion failed: ${error.message}`,
138+
}

sim/app/tools/perplexity/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { chatTool } from './chat'
2+
3+
export const perplexityChatTool = chatTool

sim/app/tools/perplexity/types.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { ToolResponse } from '../types'
2+
3+
export interface PerplexityMessage {
4+
role: string
5+
content: string
6+
}
7+
8+
export interface PerplexityChatParams {
9+
apiKey: string
10+
model: string
11+
messages?: PerplexityMessage[]
12+
max_tokens?: number
13+
temperature?: number
14+
15+
prompt?: string
16+
system?: string
17+
}
18+
19+
export interface PerplexityChatResponse extends ToolResponse {
20+
output: {
21+
content: string
22+
model: string
23+
usage: {
24+
prompt_tokens: number
25+
completion_tokens: number
26+
total_tokens: number
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)