mcp-perplexity-pro 1.1.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/README.md +638 -0
- package/bin/mcp-perplexity-pro +8 -0
- package/bin/mcp-perplexity-pro-stdio +9 -0
- package/dist/claude-code-bridge.d.ts +3 -0
- package/dist/claude-code-bridge.d.ts.map +1 -0
- package/dist/claude-code-bridge.js +111 -0
- package/dist/claude-code-bridge.js.map +1 -0
- package/dist/http-index.d.ts +3 -0
- package/dist/http-index.d.ts.map +1 -0
- package/dist/http-index.js +38 -0
- package/dist/http-index.js.map +1 -0
- package/dist/http-server.d.ts +33 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +362 -0
- package/dist/http-server.js.map +1 -0
- package/dist/http-streaming-server.d.ts +4 -0
- package/dist/http-streaming-server.d.ts.map +1 -0
- package/dist/http-streaming-server.js +514 -0
- package/dist/http-streaming-server.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/launcher.d.ts +3 -0
- package/dist/launcher.d.ts.map +1 -0
- package/dist/launcher.js +209 -0
- package/dist/launcher.js.map +1 -0
- package/dist/mcp-server.d.ts +5 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +329 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/models.d.ts +45 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +284 -0
- package/dist/models.js.map +1 -0
- package/dist/perplexity-api.d.ts +59 -0
- package/dist/perplexity-api.d.ts.map +1 -0
- package/dist/perplexity-api.js +455 -0
- package/dist/perplexity-api.js.map +1 -0
- package/dist/port-utils.d.ts +31 -0
- package/dist/port-utils.d.ts.map +1 -0
- package/dist/port-utils.js +114 -0
- package/dist/port-utils.js.map +1 -0
- package/dist/project-manager.d.ts +91 -0
- package/dist/project-manager.d.ts.map +1 -0
- package/dist/project-manager.js +422 -0
- package/dist/project-manager.js.map +1 -0
- package/dist/simple-streaming.d.ts +26 -0
- package/dist/simple-streaming.d.ts.map +1 -0
- package/dist/simple-streaming.js +75 -0
- package/dist/simple-streaming.js.map +1 -0
- package/dist/sse-index.d.ts +3 -0
- package/dist/sse-index.d.ts.map +1 -0
- package/dist/sse-index.js +38 -0
- package/dist/sse-index.js.map +1 -0
- package/dist/sse-server.d.ts +4 -0
- package/dist/sse-server.d.ts.map +1 -0
- package/dist/sse-server.js +208 -0
- package/dist/sse-server.js.map +1 -0
- package/dist/stdio-bridge.d.ts +21 -0
- package/dist/stdio-bridge.d.ts.map +1 -0
- package/dist/stdio-bridge.js +157 -0
- package/dist/stdio-bridge.js.map +1 -0
- package/dist/stdio-server.d.ts +7 -0
- package/dist/stdio-server.d.ts.map +1 -0
- package/dist/stdio-server.js +396 -0
- package/dist/stdio-server.js.map +1 -0
- package/dist/storage.d.ts +65 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +328 -0
- package/dist/storage.js.map +1 -0
- package/dist/streaming-wrapper.d.ts +63 -0
- package/dist/streaming-wrapper.d.ts.map +1 -0
- package/dist/streaming-wrapper.js +452 -0
- package/dist/streaming-wrapper.js.map +1 -0
- package/dist/tools/async.d.ts +28 -0
- package/dist/tools/async.d.ts.map +1 -0
- package/dist/tools/async.js +167 -0
- package/dist/tools/async.js.map +1 -0
- package/dist/tools/chat.d.ts +29 -0
- package/dist/tools/chat.d.ts.map +1 -0
- package/dist/tools/chat.js +233 -0
- package/dist/tools/chat.js.map +1 -0
- package/dist/tools/projects.d.ts +19 -0
- package/dist/tools/projects.d.ts.map +1 -0
- package/dist/tools/projects.js +219 -0
- package/dist/tools/projects.js.map +1 -0
- package/dist/tools/query.d.ts +13 -0
- package/dist/tools/query.d.ts.map +1 -0
- package/dist/tools/query.js +178 -0
- package/dist/tools/query.js.map +1 -0
- package/dist/types.d.ts +330 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +90 -0
- package/dist/types.js.map +1 -0
- package/package.json +89 -0
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
import { PerplexityApiClient } from './perplexity-api.js';
|
|
2
|
+
import { selectOptimalModel } from './models.js';
|
|
3
|
+
/**
|
|
4
|
+
* Active streaming operations registry
|
|
5
|
+
*/
|
|
6
|
+
const activeStreams = new Map();
|
|
7
|
+
/**
|
|
8
|
+
* Universal async tool wrapper that creates async jobs and streams progress to Claude Code
|
|
9
|
+
*/
|
|
10
|
+
export class StreamingWrapper {
|
|
11
|
+
server;
|
|
12
|
+
config;
|
|
13
|
+
constructor(server, config) {
|
|
14
|
+
this.server = server;
|
|
15
|
+
this.config = config;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Execute a tool call with streaming content updates (not just progress)
|
|
19
|
+
*/
|
|
20
|
+
async executeWithStreaming(toolName, params, progressToken) {
|
|
21
|
+
// If no progress token provided, execute synchronously (backwards compatibility)
|
|
22
|
+
if (!progressToken) {
|
|
23
|
+
return this.executeSynchronously(toolName, params);
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
// Create async job based on tool type
|
|
27
|
+
const asyncJob = await this.createAsyncJob(toolName, params);
|
|
28
|
+
if ('error' in asyncJob) {
|
|
29
|
+
return asyncJob;
|
|
30
|
+
}
|
|
31
|
+
// Register streaming state
|
|
32
|
+
const streamState = {
|
|
33
|
+
jobId: asyncJob.id,
|
|
34
|
+
progressToken,
|
|
35
|
+
server: this.server,
|
|
36
|
+
startTime: Date.now(),
|
|
37
|
+
lastProgress: 0,
|
|
38
|
+
toolName,
|
|
39
|
+
params,
|
|
40
|
+
config: this.config,
|
|
41
|
+
};
|
|
42
|
+
activeStreams.set(asyncJob.id, streamState);
|
|
43
|
+
// Start streaming content (not just progress)
|
|
44
|
+
this.startContentStreaming(asyncJob.id);
|
|
45
|
+
// Return initial response indicating streaming has started
|
|
46
|
+
return {
|
|
47
|
+
content: [
|
|
48
|
+
{
|
|
49
|
+
type: 'text',
|
|
50
|
+
text: `🚀 Starting ${toolName}...\n\n`,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return {
|
|
57
|
+
content: [
|
|
58
|
+
{
|
|
59
|
+
type: 'text',
|
|
60
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
isError: true,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Create async job based on tool type
|
|
69
|
+
*/
|
|
70
|
+
async createAsyncJob(toolName, params) {
|
|
71
|
+
const apiClient = new PerplexityApiClient(this.config);
|
|
72
|
+
// Determine the query/content based on tool type
|
|
73
|
+
let query;
|
|
74
|
+
let model;
|
|
75
|
+
switch (toolName) {
|
|
76
|
+
case 'ask_perplexity':
|
|
77
|
+
query = params.query;
|
|
78
|
+
model = params.model || selectOptimalModel(query, undefined, this.config.default_model);
|
|
79
|
+
break;
|
|
80
|
+
case 'chat_perplexity':
|
|
81
|
+
query = params.message;
|
|
82
|
+
model = params.model || selectOptimalModel(query, undefined, this.config.default_model);
|
|
83
|
+
break;
|
|
84
|
+
case 'research_perplexity':
|
|
85
|
+
query = params.topic;
|
|
86
|
+
model = params.model || 'sonar-deep-research';
|
|
87
|
+
break;
|
|
88
|
+
default:
|
|
89
|
+
throw new Error(`Unsupported tool for streaming: ${toolName}`);
|
|
90
|
+
}
|
|
91
|
+
// Create the async request
|
|
92
|
+
const request = {
|
|
93
|
+
model,
|
|
94
|
+
messages: [{ role: 'user', content: query }],
|
|
95
|
+
temperature: params.temperature ?? 0.2,
|
|
96
|
+
...(params.max_tokens && { max_tokens: params.max_tokens }),
|
|
97
|
+
...(params.search_domain_filter && { search_domain_filter: params.search_domain_filter }),
|
|
98
|
+
...(params.return_images && { return_images: params.return_images }),
|
|
99
|
+
...(params.return_related_questions && {
|
|
100
|
+
return_related_questions: params.return_related_questions,
|
|
101
|
+
}),
|
|
102
|
+
};
|
|
103
|
+
return await apiClient.createAsyncChatCompletion(request);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Execute tool synchronously (fallback for no progress token)
|
|
107
|
+
*/
|
|
108
|
+
async executeSynchronously(toolName, params) {
|
|
109
|
+
// Import handlers dynamically to avoid circular dependencies
|
|
110
|
+
const { handleAskPerplexity, handleResearchPerplexity } = await import('./tools/query.js');
|
|
111
|
+
const { handleChatPerplexity } = await import('./tools/chat.js');
|
|
112
|
+
switch (toolName) {
|
|
113
|
+
case 'ask_perplexity':
|
|
114
|
+
return await handleAskPerplexity(params, this.config);
|
|
115
|
+
case 'chat_perplexity': {
|
|
116
|
+
const result = await handleChatPerplexity(params, this.config);
|
|
117
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
118
|
+
}
|
|
119
|
+
case 'research_perplexity': {
|
|
120
|
+
const researchResult = await handleResearchPerplexity(params, this.config);
|
|
121
|
+
return { content: [{ type: 'text', text: JSON.stringify(researchResult, null, 2) }] };
|
|
122
|
+
}
|
|
123
|
+
default:
|
|
124
|
+
throw new Error(`Unknown tool: ${toolName}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Start streaming actual content from async job (not just progress)
|
|
129
|
+
*/
|
|
130
|
+
async startContentStreaming(jobId) {
|
|
131
|
+
const state = activeStreams.get(jobId);
|
|
132
|
+
if (!state)
|
|
133
|
+
return;
|
|
134
|
+
const apiClient = new PerplexityApiClient(this.config);
|
|
135
|
+
let pollCount = 0;
|
|
136
|
+
let lastContentLength = 0;
|
|
137
|
+
const maxPolls = 60; // 5 minutes max (5s intervals)
|
|
138
|
+
const pollAndStreamContent = async () => {
|
|
139
|
+
try {
|
|
140
|
+
const jobStatus = await apiClient.getAsyncJob(jobId);
|
|
141
|
+
if (!activeStreams.has(jobId)) {
|
|
142
|
+
// Stream was cancelled
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
pollCount++;
|
|
146
|
+
// Check if we have new content to stream
|
|
147
|
+
const currentContent = jobStatus.choices?.[0]?.message?.content || '';
|
|
148
|
+
if (currentContent.length > lastContentLength) {
|
|
149
|
+
// We have new content! Stream the delta
|
|
150
|
+
const newContent = currentContent.slice(lastContentLength);
|
|
151
|
+
await this.streamContentChunk(state, newContent, jobStatus.status);
|
|
152
|
+
lastContentLength = currentContent.length;
|
|
153
|
+
}
|
|
154
|
+
// Send status updates for major state changes
|
|
155
|
+
if (jobStatus.status === 'STARTED' && state.lastProgress < 25) {
|
|
156
|
+
await this.streamContentChunk(state, '📡 Processing your request...\n\n', jobStatus.status);
|
|
157
|
+
state.lastProgress = 25;
|
|
158
|
+
}
|
|
159
|
+
// Handle completion
|
|
160
|
+
if (jobStatus.status === 'COMPLETED') {
|
|
161
|
+
// Stream any remaining content
|
|
162
|
+
if (currentContent.length > lastContentLength) {
|
|
163
|
+
const finalContent = currentContent.slice(lastContentLength);
|
|
164
|
+
await this.streamContentChunk(state, finalContent, jobStatus.status);
|
|
165
|
+
}
|
|
166
|
+
// Process final job result (save report, etc.)
|
|
167
|
+
await this.handleJobCompletion(jobId, jobStatus);
|
|
168
|
+
// Stream completion message
|
|
169
|
+
await this.streamContentChunk(state, '\n\n✅ Complete!', 'COMPLETED');
|
|
170
|
+
activeStreams.delete(jobId);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
else if (jobStatus.status === 'FAILED') {
|
|
174
|
+
await this.streamContentChunk(state, `\n\n❌ Job failed: ${jobStatus.error || 'Unknown error'}`, 'FAILED');
|
|
175
|
+
activeStreams.delete(jobId);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
// Continue polling if job is still running
|
|
179
|
+
if (pollCount < maxPolls &&
|
|
180
|
+
(jobStatus.status === 'CREATED' || jobStatus.status === 'STARTED')) {
|
|
181
|
+
setTimeout(pollAndStreamContent, 2000); // Poll every 2 seconds for more responsive streaming
|
|
182
|
+
}
|
|
183
|
+
else if (pollCount >= maxPolls) {
|
|
184
|
+
// Timeout reached
|
|
185
|
+
await this.streamContentChunk(state, '\n\n⏰ Request timed out after 5 minutes', 'FAILED');
|
|
186
|
+
activeStreams.delete(jobId);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
console.error(`Error polling job ${jobId}:`, error);
|
|
191
|
+
await this.streamContentChunk(state, `\n\n❌ Error: ${error instanceof Error ? error.message : String(error)}`, 'FAILED');
|
|
192
|
+
activeStreams.delete(jobId);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
// Start polling immediately
|
|
196
|
+
setTimeout(pollAndStreamContent, 500); // Start after 500ms
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Stream a chunk of content to Claude Code
|
|
200
|
+
*/
|
|
201
|
+
async streamContentChunk(state, content, status) {
|
|
202
|
+
try {
|
|
203
|
+
// Use MCP's streaming capabilities to send partial content
|
|
204
|
+
// This creates the illusion of real-time streaming by sending content in chunks
|
|
205
|
+
await state.server.notification({
|
|
206
|
+
method: 'notifications/message',
|
|
207
|
+
params: {
|
|
208
|
+
level: 'info',
|
|
209
|
+
logger: `mcp-perplexity-${state.toolName}`,
|
|
210
|
+
data: {
|
|
211
|
+
type: 'content_chunk',
|
|
212
|
+
content: content,
|
|
213
|
+
job_id: state.jobId,
|
|
214
|
+
status: status,
|
|
215
|
+
timestamp: Date.now(),
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
// Also send to stdout for CLI clients that capture output
|
|
220
|
+
process.stdout.write(content);
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
console.error('Error streaming content chunk:', error);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Legacy method - keeping for backwards compatibility
|
|
228
|
+
*/
|
|
229
|
+
async startProgressStreaming(jobId) {
|
|
230
|
+
const state = activeStreams.get(jobId);
|
|
231
|
+
if (!state)
|
|
232
|
+
return;
|
|
233
|
+
const apiClient = new PerplexityApiClient(this.config);
|
|
234
|
+
let pollCount = 0;
|
|
235
|
+
const maxPolls = 60; // 5 minutes max (5s intervals)
|
|
236
|
+
const pollProgress = async () => {
|
|
237
|
+
try {
|
|
238
|
+
const jobStatus = await apiClient.getAsyncJob(jobId);
|
|
239
|
+
if (!activeStreams.has(jobId)) {
|
|
240
|
+
// Stream was cancelled
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
pollCount++;
|
|
244
|
+
// Calculate progress based on status and elapsed time
|
|
245
|
+
let progress = state.lastProgress;
|
|
246
|
+
let total = 100;
|
|
247
|
+
switch (jobStatus.status) {
|
|
248
|
+
case 'CREATED':
|
|
249
|
+
progress = Math.min(10 + pollCount * 2, 20);
|
|
250
|
+
break;
|
|
251
|
+
case 'STARTED':
|
|
252
|
+
progress = Math.min(25 + pollCount * 3, 80);
|
|
253
|
+
break;
|
|
254
|
+
case 'COMPLETED':
|
|
255
|
+
progress = 100;
|
|
256
|
+
break;
|
|
257
|
+
case 'FAILED':
|
|
258
|
+
progress = 0;
|
|
259
|
+
total = 0;
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
// Only send progress update if progress increased
|
|
263
|
+
if (progress > state.lastProgress ||
|
|
264
|
+
jobStatus.status === 'COMPLETED' ||
|
|
265
|
+
jobStatus.status === 'FAILED') {
|
|
266
|
+
await this.sendProgressNotification(state, progress, total, jobStatus);
|
|
267
|
+
state.lastProgress = progress;
|
|
268
|
+
}
|
|
269
|
+
// Handle completion or failure
|
|
270
|
+
if (jobStatus.status === 'COMPLETED') {
|
|
271
|
+
await this.handleJobCompletion(jobId, jobStatus);
|
|
272
|
+
activeStreams.delete(jobId);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
else if (jobStatus.status === 'FAILED') {
|
|
276
|
+
await this.handleJobFailure(jobId, jobStatus);
|
|
277
|
+
activeStreams.delete(jobId);
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
// Continue polling if job is still running and we haven't exceeded max polls
|
|
281
|
+
if (pollCount < maxPolls &&
|
|
282
|
+
(jobStatus.status === 'CREATED' || jobStatus.status === 'STARTED')) {
|
|
283
|
+
setTimeout(pollProgress, 5000); // Poll every 5 seconds
|
|
284
|
+
}
|
|
285
|
+
else if (pollCount >= maxPolls) {
|
|
286
|
+
// Timeout reached
|
|
287
|
+
await this.sendProgressNotification(state, 0, 0, {
|
|
288
|
+
...jobStatus,
|
|
289
|
+
status: 'FAILED',
|
|
290
|
+
error: 'Job timed out after 5 minutes',
|
|
291
|
+
});
|
|
292
|
+
activeStreams.delete(jobId);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
console.error(`Error polling job ${jobId}:`, error);
|
|
297
|
+
// Send error notification
|
|
298
|
+
await this.sendProgressNotification(state, 0, 0, {
|
|
299
|
+
id: jobId,
|
|
300
|
+
status: 'FAILED',
|
|
301
|
+
error: error instanceof Error ? error.message : String(error),
|
|
302
|
+
created_at: Math.floor(Date.now() / 1000),
|
|
303
|
+
model: 'unknown',
|
|
304
|
+
});
|
|
305
|
+
activeStreams.delete(jobId);
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
// Start polling
|
|
309
|
+
setTimeout(pollProgress, 1000); // Start after 1 second
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Send progress notification to Claude Code
|
|
313
|
+
*/
|
|
314
|
+
async sendProgressNotification(state, progress, total, jobStatus) {
|
|
315
|
+
try {
|
|
316
|
+
const elapsedTime = Date.now() - state.startTime;
|
|
317
|
+
const statusMessage = this.getStatusMessage(jobStatus.status, progress, elapsedTime);
|
|
318
|
+
// Send MCP progress notification
|
|
319
|
+
await state.server.notification({
|
|
320
|
+
method: 'notifications/progress',
|
|
321
|
+
params: {
|
|
322
|
+
progressToken: state.progressToken,
|
|
323
|
+
progress,
|
|
324
|
+
total,
|
|
325
|
+
_meta: {
|
|
326
|
+
status: jobStatus.status,
|
|
327
|
+
job_id: jobStatus.id,
|
|
328
|
+
tool_name: state.toolName,
|
|
329
|
+
elapsed_time_ms: elapsedTime,
|
|
330
|
+
message: statusMessage,
|
|
331
|
+
...(jobStatus.error && { error: jobStatus.error }),
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
catch (error) {
|
|
337
|
+
console.error('Error sending progress notification:', error);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Handle job completion and send final result
|
|
342
|
+
*/
|
|
343
|
+
async handleJobCompletion(jobId, jobStatus) {
|
|
344
|
+
const state = activeStreams.get(jobId);
|
|
345
|
+
if (!state)
|
|
346
|
+
return;
|
|
347
|
+
try {
|
|
348
|
+
// Process the completed result based on tool type
|
|
349
|
+
const finalResult = await this.processCompletedJob(state.toolName, state.params, jobStatus);
|
|
350
|
+
// Send final progress notification with result
|
|
351
|
+
await state.server.notification({
|
|
352
|
+
method: 'notifications/progress',
|
|
353
|
+
params: {
|
|
354
|
+
progressToken: state.progressToken,
|
|
355
|
+
progress: 100,
|
|
356
|
+
total: 100,
|
|
357
|
+
_meta: {
|
|
358
|
+
status: 'COMPLETED',
|
|
359
|
+
job_id: jobId,
|
|
360
|
+
tool_name: state.toolName,
|
|
361
|
+
elapsed_time_ms: Date.now() - state.startTime,
|
|
362
|
+
message: 'Completed successfully',
|
|
363
|
+
final_result: finalResult,
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
catch (error) {
|
|
369
|
+
console.error(`Error handling job completion for ${jobId}:`, error);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Handle job failure
|
|
374
|
+
*/
|
|
375
|
+
async handleJobFailure(jobId, jobStatus) {
|
|
376
|
+
const state = activeStreams.get(jobId);
|
|
377
|
+
if (!state)
|
|
378
|
+
return;
|
|
379
|
+
await this.sendProgressNotification(state, 0, 0, jobStatus);
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Process completed job based on tool type
|
|
383
|
+
*/
|
|
384
|
+
async processCompletedJob(toolName, params, jobStatus) {
|
|
385
|
+
// Save report if requested
|
|
386
|
+
if (params.save_report && jobStatus.choices?.[0]?.message?.content) {
|
|
387
|
+
const { StorageManager } = await import('./storage.js');
|
|
388
|
+
const { detectProjectWithSuggestions } = await import('./tools/projects.js');
|
|
389
|
+
const projectName = params.project_name || (await detectProjectWithSuggestions(undefined, this.config));
|
|
390
|
+
const toolSubdir = toolName.replace('_perplexity', '');
|
|
391
|
+
const projectConfig = {
|
|
392
|
+
...this.config,
|
|
393
|
+
storage_path: `projects/${projectName}/${toolSubdir}`,
|
|
394
|
+
};
|
|
395
|
+
const storageManager = new StorageManager(projectConfig);
|
|
396
|
+
let reportContent;
|
|
397
|
+
switch (toolName) {
|
|
398
|
+
case 'ask_perplexity':
|
|
399
|
+
reportContent = `# Ask Perplexity Report\n\n**Query:** ${params.query}\n**Model:** ${jobStatus.model}\n**Timestamp:** ${new Date().toISOString()}\n\n## Response\n\n${jobStatus.choices[0].message.content}`;
|
|
400
|
+
break;
|
|
401
|
+
case 'research_perplexity':
|
|
402
|
+
reportContent = `# Research Report\n\n**Topic:** ${params.topic}\n**Model:** ${jobStatus.model}\n**Timestamp:** ${new Date().toISOString()}\n\n## Research Results\n\n${jobStatus.choices[0].message.content}`;
|
|
403
|
+
break;
|
|
404
|
+
case 'chat_perplexity':
|
|
405
|
+
reportContent = `# Chat Export\n\n**Message:** ${params.message}\n**Model:** ${jobStatus.model}\n**Timestamp:** ${new Date().toISOString()}\n\n## Response\n\n${jobStatus.choices[0].message.content}`;
|
|
406
|
+
break;
|
|
407
|
+
default:
|
|
408
|
+
reportContent = `# ${toolName} Report\n\n${jobStatus.choices[0].message.content}`;
|
|
409
|
+
}
|
|
410
|
+
await storageManager.saveReport(reportContent, `${toolName}-${Date.now()}`);
|
|
411
|
+
}
|
|
412
|
+
return {
|
|
413
|
+
job_id: jobStatus.id,
|
|
414
|
+
status: jobStatus.status,
|
|
415
|
+
model: jobStatus.model,
|
|
416
|
+
response: jobStatus.choices?.[0]?.message?.content || 'No response content',
|
|
417
|
+
usage: jobStatus.usage,
|
|
418
|
+
...(params.save_report && { report_saved: true }),
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Get status message for progress updates
|
|
423
|
+
*/
|
|
424
|
+
getStatusMessage(status, progress, elapsedTime) {
|
|
425
|
+
const elapsedSeconds = Math.floor(elapsedTime / 1000);
|
|
426
|
+
switch (status) {
|
|
427
|
+
case 'CREATED':
|
|
428
|
+
return `Job created, waiting to start... (${elapsedSeconds}s)`;
|
|
429
|
+
case 'STARTED':
|
|
430
|
+
return `Processing... ${progress}% complete (${elapsedSeconds}s)`;
|
|
431
|
+
case 'COMPLETED':
|
|
432
|
+
return `Completed successfully! (${elapsedSeconds}s total)`;
|
|
433
|
+
case 'FAILED':
|
|
434
|
+
return `Job failed (${elapsedSeconds}s)`;
|
|
435
|
+
default:
|
|
436
|
+
return `Status: ${status} (${elapsedSeconds}s)`;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Cancel streaming for a job
|
|
441
|
+
*/
|
|
442
|
+
cancelStreaming(jobId) {
|
|
443
|
+
activeStreams.delete(jobId);
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Get active streaming jobs
|
|
447
|
+
*/
|
|
448
|
+
getActiveStreams() {
|
|
449
|
+
return Array.from(activeStreams.keys());
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
//# sourceMappingURL=streaming-wrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming-wrapper.js","sourceRoot":"","sources":["../src/streaming-wrapper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AsyncPerplexityParams, CheckAsyncParams, Config, AsyncJob, ErrorResponse } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Handles the async_perplexity tool - creates async jobs for long-running queries
|
|
4
|
+
*/
|
|
5
|
+
export declare function handleAsyncPerplexity(params: AsyncPerplexityParams, config: Config): Promise<(AsyncJob & {
|
|
6
|
+
selected_model: string;
|
|
7
|
+
model_selection_reason: string;
|
|
8
|
+
estimated_completion: string;
|
|
9
|
+
}) | ErrorResponse>;
|
|
10
|
+
/**
|
|
11
|
+
* Handles the check_async_perplexity tool - checks status of async jobs
|
|
12
|
+
*/
|
|
13
|
+
export declare function handleCheckAsync(params: CheckAsyncParams, config: Config): Promise<(AsyncJob & {
|
|
14
|
+
completion_percentage?: number;
|
|
15
|
+
next_check_recommended?: string;
|
|
16
|
+
}) | ErrorResponse>;
|
|
17
|
+
/**
|
|
18
|
+
* Handles the list_async_jobs tool - lists all async jobs
|
|
19
|
+
*/
|
|
20
|
+
export declare function handleListAsyncJobs(config: Config, limit?: number, nextToken?: string): Promise<{
|
|
21
|
+
jobs: (AsyncJob & {
|
|
22
|
+
time_since_created: string;
|
|
23
|
+
estimated_time_remaining?: string;
|
|
24
|
+
})[];
|
|
25
|
+
next_token?: string;
|
|
26
|
+
total_jobs: number;
|
|
27
|
+
} | ErrorResponse>;
|
|
28
|
+
//# sourceMappingURL=async.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async.d.ts","sourceRoot":"","sources":["../../src/tools/async.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,gBAAgB,EAChB,MAAM,EACN,QAAQ,EACR,aAAa,EACd,MAAM,aAAa,CAAC;AAIrB;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,qBAAqB,EAC7B,MAAM,EAAE,MAAM,GACb,OAAO,CACN,CAAC,QAAQ,GAAG;IACV,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC,GACF,aAAa,CAChB,CAyCA;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,MAAM,GACb,OAAO,CACN,CAAC,QAAQ,GAAG;IACV,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC,CAAC,GACF,aAAa,CAChB,CA0CA;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,KAAK,SAAK,EACV,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CACN;IACE,IAAI,EAAE,CAAC,QAAQ,GAAG;QAAE,kBAAkB,EAAE,MAAM,CAAC;QAAC,wBAAwB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IACvF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB,GACD,aAAa,CAChB,CAsCA"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { PerplexityApiClient } from '../perplexity-api.js';
|
|
2
|
+
import { selectOptimalModel } from '../models.js';
|
|
3
|
+
/**
|
|
4
|
+
* Handles the async_perplexity tool - creates async jobs for long-running queries
|
|
5
|
+
*/
|
|
6
|
+
export async function handleAsyncPerplexity(params, config) {
|
|
7
|
+
try {
|
|
8
|
+
const apiClient = new PerplexityApiClient(config);
|
|
9
|
+
// Detect project for potential report saving (not currently used)
|
|
10
|
+
// const { detectProjectWithSuggestions } = await import('./projects.js');
|
|
11
|
+
// const projectName = await detectProjectWithSuggestions(undefined, config);
|
|
12
|
+
// Select optimal model based on query or use explicit model
|
|
13
|
+
const selectedModel = selectOptimalModel(params.query, params.model, config.default_model);
|
|
14
|
+
// Prepare the async request
|
|
15
|
+
const request = {
|
|
16
|
+
model: selectedModel,
|
|
17
|
+
messages: [{ role: 'user', content: params.query }],
|
|
18
|
+
temperature: params.temperature ?? 0.2,
|
|
19
|
+
...(params.max_tokens && { max_tokens: params.max_tokens }),
|
|
20
|
+
};
|
|
21
|
+
const response = await apiClient.createAsyncChatCompletion(request);
|
|
22
|
+
// Estimate completion time based on model type and complexity
|
|
23
|
+
const estimatedMinutes = getEstimatedCompletionTime(selectedModel, params.query);
|
|
24
|
+
const estimatedCompletion = new Date(Date.now() + estimatedMinutes * 60 * 1000).toISOString();
|
|
25
|
+
return {
|
|
26
|
+
...response,
|
|
27
|
+
selected_model: selectedModel,
|
|
28
|
+
model_selection_reason: params.model ? 'user_specified' : 'auto_selected',
|
|
29
|
+
estimated_completion: estimatedCompletion,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
return PerplexityApiClient.handleError(error, {
|
|
34
|
+
model: params.model || config.default_model,
|
|
35
|
+
query: params.query,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Handles the check_async_perplexity tool - checks status of async jobs
|
|
41
|
+
*/
|
|
42
|
+
export async function handleCheckAsync(params, config) {
|
|
43
|
+
try {
|
|
44
|
+
const apiClient = new PerplexityApiClient(config);
|
|
45
|
+
// Note: async job checking doesn't need project-aware config since
|
|
46
|
+
// job IDs are global and not project-specific
|
|
47
|
+
const response = await apiClient.getAsyncJob(params.job_id);
|
|
48
|
+
// Add helpful metadata for job monitoring
|
|
49
|
+
let completionPercentage;
|
|
50
|
+
let nextCheckRecommended;
|
|
51
|
+
switch (response.status) {
|
|
52
|
+
case 'CREATED':
|
|
53
|
+
completionPercentage = 10;
|
|
54
|
+
nextCheckRecommended = new Date(Date.now() + 30 * 1000).toISOString(); // 30 seconds
|
|
55
|
+
break;
|
|
56
|
+
case 'STARTED':
|
|
57
|
+
completionPercentage = 50;
|
|
58
|
+
nextCheckRecommended = new Date(Date.now() + 60 * 1000).toISOString(); // 1 minute
|
|
59
|
+
break;
|
|
60
|
+
case 'COMPLETED':
|
|
61
|
+
completionPercentage = 100;
|
|
62
|
+
break;
|
|
63
|
+
case 'FAILED':
|
|
64
|
+
completionPercentage = 0;
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
...response,
|
|
69
|
+
...(completionPercentage !== undefined && { completion_percentage: completionPercentage }),
|
|
70
|
+
...(nextCheckRecommended && { next_check_recommended: nextCheckRecommended }),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return PerplexityApiClient.handleError(error, {
|
|
75
|
+
query: `Async job check: ${params.job_id}`,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Handles the list_async_jobs tool - lists all async jobs
|
|
81
|
+
*/
|
|
82
|
+
export async function handleListAsyncJobs(config, limit = 20, nextToken) {
|
|
83
|
+
try {
|
|
84
|
+
const apiClient = new PerplexityApiClient(config);
|
|
85
|
+
// Note: listing async jobs doesn't need project-aware config since
|
|
86
|
+
// jobs are listed globally, not per project
|
|
87
|
+
const response = await apiClient.listAsyncJobs(limit, nextToken);
|
|
88
|
+
// Add helpful metadata to each job
|
|
89
|
+
const enrichedJobs = (response.jobs || []).map(job => {
|
|
90
|
+
const timeSinceCreated = formatTimeDuration(Date.now() - job.created_at * 1000);
|
|
91
|
+
let estimatedTimeRemaining;
|
|
92
|
+
// Estimate remaining time for active jobs
|
|
93
|
+
if (job.status === 'CREATED' || job.status === 'STARTED') {
|
|
94
|
+
const elapsedMinutes = (Date.now() - job.created_at * 1000) / (1000 * 60);
|
|
95
|
+
const estimatedTotalMinutes = getEstimatedCompletionTime(job.model, 'complex query');
|
|
96
|
+
const remainingMinutes = Math.max(0, estimatedTotalMinutes - elapsedMinutes);
|
|
97
|
+
estimatedTimeRemaining = `${Math.ceil(remainingMinutes)} minutes`;
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
...job,
|
|
101
|
+
time_since_created: timeSinceCreated,
|
|
102
|
+
...(estimatedTimeRemaining && { estimated_time_remaining: estimatedTimeRemaining }),
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
return {
|
|
106
|
+
jobs: enrichedJobs,
|
|
107
|
+
...(response.next_token && { next_token: response.next_token }),
|
|
108
|
+
total_jobs: (response.jobs || []).length,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
return PerplexityApiClient.handleError(error, {
|
|
113
|
+
query: 'List async jobs',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Estimates completion time based on model and query complexity
|
|
119
|
+
*/
|
|
120
|
+
function getEstimatedCompletionTime(model, query) {
|
|
121
|
+
// Base times in minutes
|
|
122
|
+
const baseTimes = {
|
|
123
|
+
sonar: 0.5,
|
|
124
|
+
'sonar-pro': 1,
|
|
125
|
+
'sonar-reasoning': 1.5,
|
|
126
|
+
'sonar-reasoning-pro': 3,
|
|
127
|
+
'sonar-deep-research': 5,
|
|
128
|
+
};
|
|
129
|
+
let baseTime = baseTimes[model] || 2;
|
|
130
|
+
// Adjust based on query complexity
|
|
131
|
+
const queryLength = query.length;
|
|
132
|
+
const complexityKeywords = [
|
|
133
|
+
'comprehensive',
|
|
134
|
+
'detailed',
|
|
135
|
+
'analysis',
|
|
136
|
+
'research',
|
|
137
|
+
'compare',
|
|
138
|
+
'evaluate',
|
|
139
|
+
'investigate',
|
|
140
|
+
];
|
|
141
|
+
// Add time for query length
|
|
142
|
+
if (queryLength > 500)
|
|
143
|
+
baseTime *= 1.5;
|
|
144
|
+
else if (queryLength > 200)
|
|
145
|
+
baseTime *= 1.2;
|
|
146
|
+
// Add time for complexity keywords
|
|
147
|
+
const complexityScore = complexityKeywords.reduce((score, keyword) => score + (query.toLowerCase().includes(keyword) ? 1 : 0), 0);
|
|
148
|
+
baseTime *= 1 + complexityScore * 0.3;
|
|
149
|
+
return Math.ceil(baseTime);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Formats time duration in a human-readable format
|
|
153
|
+
*/
|
|
154
|
+
function formatTimeDuration(milliseconds) {
|
|
155
|
+
const seconds = Math.floor(milliseconds / 1000);
|
|
156
|
+
const minutes = Math.floor(seconds / 60);
|
|
157
|
+
const hours = Math.floor(minutes / 60);
|
|
158
|
+
const days = Math.floor(hours / 24);
|
|
159
|
+
if (days > 0)
|
|
160
|
+
return `${days}d ${hours % 24}h`;
|
|
161
|
+
if (hours > 0)
|
|
162
|
+
return `${hours}h ${minutes % 60}m`;
|
|
163
|
+
if (minutes > 0)
|
|
164
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
165
|
+
return `${seconds}s`;
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=async.js.map
|