pplx-zero 1.0.0 → 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 +188 -51
- package/dist/cli.js +378 -61
- package/package.json +15 -3
package/README.md
CHANGED
|
@@ -1,40 +1,53 @@
|
|
|
1
|
-
#
|
|
1
|
+
# PPLX-Zero
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Fast Perplexity AI search CLI - minimal setup, maximal results
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://badge.fury.io/js/pplx-zero"><img src="https://badge.fury.io/js/pplx-zero.svg" alt="npm version"></a>
|
|
7
|
+
<a href="https://aur.archlinux.org/packages/pplx-zero"><img src="https://img.shields.io/aur/version/pplx-zero?style=flat-square" alt="AUR package"></a>
|
|
8
|
+
<a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-007ACC?logo=typescript&logoColor=white" alt="TypeScript"></a>
|
|
9
|
+
<a href="https://bun.sh"><img src="https://img.shields.io/badge/Bun-black?logo=bun&logoColor=white" alt="Bun"></a>
|
|
10
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
|
|
11
|
+
</p>
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
A fast TypeScript CLI for Perplexity AI search with multimodal support. Built with Bun runtime for performance and reliability.
|
|
10
14
|
|
|
11
|
-
##
|
|
15
|
+
## Features
|
|
12
16
|
|
|
13
|
-
- **⚡
|
|
14
|
-
- **🎯
|
|
15
|
-
- **📦 Batch Processing** - Handle multiple
|
|
16
|
-
- **🔄 Real-time
|
|
17
|
+
- **⚡ Fast Search** - Concurrent queries with intelligent rate limiting
|
|
18
|
+
- **🎯 Simple Setup** - Works with just an API key, no configuration required
|
|
19
|
+
- **📦 Batch Processing** - Handle multiple searches simultaneously
|
|
20
|
+
- **🔄 Real-time Updates** - JSONL streaming progress events
|
|
21
|
+
- **🖼️ File Analysis** - Process documents and images with AI models
|
|
22
|
+
- **🤖 AI Models** - Sonar, Sonar Pro, Sonar Deep Research, Sonar Reasoning
|
|
17
23
|
- **🛡️ Type Safe** - Full Zod validation and TypeScript support
|
|
18
|
-
- **🌍 Cross-Platform** - Native Bun runtime
|
|
24
|
+
- **🌍 Cross-Platform** - Native Bun runtime support
|
|
19
25
|
|
|
20
|
-
##
|
|
26
|
+
## Quick Start
|
|
21
27
|
|
|
22
28
|
### 1️⃣ Install
|
|
23
29
|
|
|
24
30
|
**📦 Package Manager Installation (Recommended)**
|
|
25
31
|
|
|
32
|
+
<p align="center">
|
|
33
|
+
<a href="https://badge.fury.io/js/pplx-zero"><img src="https://badge.fury.io/js/pplx-zero.svg" alt="npm version"></a>
|
|
34
|
+
<a href="https://aur.archlinux.org/packages/pplx-zero"><img src="https://img.shields.io/aur/version/pplx-zero?style=flat-square" alt="AUR package"></a>
|
|
35
|
+
</p>
|
|
36
|
+
|
|
26
37
|
```bash
|
|
27
|
-
# npm (Node.js package manager)
|
|
38
|
+
# npm (Node.js package manager) - Global installation
|
|
28
39
|
npm install -g pplx-zero
|
|
29
40
|
|
|
30
|
-
# AUR (Arch Linux)
|
|
41
|
+
# AUR (Arch Linux) - Binary package
|
|
31
42
|
yay -S pplx-zero
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
# or manual AUR
|
|
43
|
+
|
|
44
|
+
# AUR (Arch Linux) - Manual build
|
|
35
45
|
git clone https://aur.archlinux.org/pplx-zero.git
|
|
36
46
|
cd pplx-zero
|
|
37
47
|
makepkg -si
|
|
48
|
+
|
|
49
|
+
# Verify installation
|
|
50
|
+
pplx --version
|
|
38
51
|
```
|
|
39
52
|
|
|
40
53
|
**🔨 Manual Installation**
|
|
@@ -47,42 +60,109 @@ bun install && bun run build
|
|
|
47
60
|
|
|
48
61
|
# Add to PATH
|
|
49
62
|
sudo ln -s "$(pwd)/dist/cli.js" /usr/local/bin/pplx
|
|
63
|
+
|
|
64
|
+
# Verify installation
|
|
65
|
+
pplx --version
|
|
50
66
|
```
|
|
51
67
|
|
|
52
68
|
### 2️⃣ Setup API Key
|
|
53
69
|
|
|
70
|
+
**Linux/macOS:**
|
|
54
71
|
```bash
|
|
55
|
-
export PERPLEXITY_API_KEY="your-
|
|
56
|
-
# Or use the fallback
|
|
57
|
-
export PERPLEXITY_AI_API_KEY="your-alternative-api-key"
|
|
72
|
+
export PERPLEXITY_API_KEY="your-api-key"
|
|
58
73
|
```
|
|
59
74
|
|
|
60
|
-
|
|
75
|
+
**Windows:**
|
|
76
|
+
```cmd
|
|
77
|
+
setx PERPLEXITY_API_KEY "your-api-key"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Get your API key:** https://www.perplexity.ai/account/api/keys
|
|
81
|
+
|
|
82
|
+
### 3️⃣ Start Searching (Simplified Interface)
|
|
61
83
|
|
|
62
84
|
```bash
|
|
63
|
-
#
|
|
85
|
+
# Simple search
|
|
64
86
|
pplx "latest AI developments"
|
|
65
87
|
|
|
66
|
-
#
|
|
67
|
-
pplx --
|
|
88
|
+
# Choose model for detailed analysis
|
|
89
|
+
pplx --model sonar-pro "Explain quantum computing"
|
|
68
90
|
|
|
69
|
-
#
|
|
70
|
-
|
|
91
|
+
# Analyze document (simplified syntax)
|
|
92
|
+
pplx --file report.pdf "Summarize this document"
|
|
93
|
+
|
|
94
|
+
# Analyze image (simplified syntax)
|
|
95
|
+
pplx --image screenshot.png "What does this interface do?"
|
|
96
|
+
|
|
97
|
+
# Document + image analysis
|
|
98
|
+
pplx --file data.csv --image chart.png "Analyze this data"
|
|
99
|
+
|
|
100
|
+
# Advanced AI models
|
|
101
|
+
pplx --model sonar-reasoning "Solve this math problem"
|
|
102
|
+
pplx --model sonar-deep-research "History of artificial intelligence"
|
|
103
|
+
|
|
104
|
+
# See basic help
|
|
105
|
+
pplx --help
|
|
106
|
+
|
|
107
|
+
# See advanced options
|
|
108
|
+
pplx --help-advanced
|
|
71
109
|
```
|
|
72
110
|
|
|
73
|
-
|
|
111
|
+
**🔄 Migration from v1.0.x:**
|
|
112
|
+
```bash
|
|
113
|
+
# OLD: pplx --format jsonl --input queries.json "search"
|
|
114
|
+
# NEW: pplx --format jsonl --input queries.json "search" # format flag unchanged
|
|
74
115
|
|
|
75
|
-
|
|
116
|
+
# OLD: pplx --attach document.pdf "analyze"
|
|
117
|
+
# NEW: pplx --file document.pdf "analyze" # simplified syntax
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Usage Guide
|
|
76
121
|
|
|
122
|
+
### Command Line Options
|
|
123
|
+
|
|
124
|
+
**Simplified Interface (Everyday Usage):**
|
|
77
125
|
```bash
|
|
78
|
-
# Basic
|
|
79
|
-
pplx
|
|
126
|
+
# Basic search with model selection
|
|
127
|
+
pplx --model sonar-pro "Detailed analysis"
|
|
128
|
+
|
|
129
|
+
# File attachments (simplified syntax)
|
|
130
|
+
pplx --file document.pdf "Summarize this report"
|
|
131
|
+
pplx --image chart.png "Analyze this chart"
|
|
80
132
|
|
|
81
|
-
#
|
|
133
|
+
# Multiple attachments
|
|
134
|
+
pplx --file doc1.pdf --image img1.png "Analyze these files"
|
|
135
|
+
|
|
136
|
+
# Output format selection
|
|
137
|
+
pplx --format jsonl "Machine learning trends"
|
|
138
|
+
|
|
139
|
+
# Choose AI models
|
|
140
|
+
pplx --model sonar-pro "Detailed analysis"
|
|
141
|
+
pplx --model sonar-reasoning "Complex problem solving"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Advanced Interface (Power Users):**
|
|
145
|
+
```bash
|
|
146
|
+
# Custom concurrency and timeout
|
|
82
147
|
pplx --concurrency 10 --timeout 60000 --format jsonl "machine learning trends"
|
|
83
148
|
|
|
84
|
-
#
|
|
85
|
-
pplx --
|
|
149
|
+
# Batch processing
|
|
150
|
+
pplx --input queries.json --concurrency 5
|
|
151
|
+
|
|
152
|
+
# Stream processing
|
|
153
|
+
cat queries.jsonl | pplx --stdin
|
|
154
|
+
|
|
155
|
+
# Advanced attachments (multiple files)
|
|
156
|
+
pplx --attach doc1.pdf --attach doc2.txt --attach-image img1.png "Analyze all files"
|
|
157
|
+
|
|
158
|
+
# Async processing with webhook
|
|
159
|
+
pplx --async --webhook https://api.example.com/callback "Research task"
|
|
160
|
+
|
|
161
|
+
# Custom workspace
|
|
162
|
+
pplx --workspace /tmp/research "Custom workspace search"
|
|
163
|
+
|
|
164
|
+
# See all advanced options
|
|
165
|
+
pplx --help-advanced
|
|
86
166
|
```
|
|
87
167
|
|
|
88
168
|
### Batch Processing
|
|
@@ -110,6 +190,28 @@ Process with:
|
|
|
110
190
|
pplx --input queries.json --format jsonl
|
|
111
191
|
```
|
|
112
192
|
|
|
193
|
+
### File Attachments
|
|
194
|
+
|
|
195
|
+
Supported file formats for analysis:
|
|
196
|
+
|
|
197
|
+
**Documents (max 50MB):**
|
|
198
|
+
- PDF, DOC, DOCX, TXT, RTF
|
|
199
|
+
|
|
200
|
+
**Images (max 50MB):**
|
|
201
|
+
- PNG, JPEG, WebP, HEIF, HEIC, GIF
|
|
202
|
+
|
|
203
|
+
**Examples:**
|
|
204
|
+
```bash
|
|
205
|
+
# Document analysis
|
|
206
|
+
pplx --attach report.pdf "Summarize this document"
|
|
207
|
+
|
|
208
|
+
# Image analysis
|
|
209
|
+
pplx --attach-image screenshot.png "Analyze this interface"
|
|
210
|
+
|
|
211
|
+
# Multiple files
|
|
212
|
+
pplx --attach document.txt --attach-image chart.png "Analyze this data"
|
|
213
|
+
```
|
|
214
|
+
|
|
113
215
|
### Programmatic Usage
|
|
114
216
|
|
|
115
217
|
```typescript
|
|
@@ -128,20 +230,55 @@ const result = await tool.runBatch({
|
|
|
128
230
|
console.log(result);
|
|
129
231
|
```
|
|
130
232
|
|
|
131
|
-
##
|
|
233
|
+
## Configuration
|
|
234
|
+
|
|
235
|
+
### Simplified Options (Everyday Usage)
|
|
236
|
+
|
|
237
|
+
| Option | Short | Type | Default | Description |
|
|
238
|
+
|--------|-------|------|---------|-------------|
|
|
239
|
+
| `--file` | `-f` | string | - | Attach document (PDF, DOC, DOCX, TXT, RTF) |
|
|
240
|
+
| `--image` | `-i` | string | - | Attach image (PNG, JPEG, WebP, HEIF, HEIC, GIF) |
|
|
241
|
+
| `--format` | `-o` | string | json | Output format: json|jsonl |
|
|
242
|
+
| `--model` | `-m` | string | sonar | AI model: sonar, sonar-pro, sonar-deep-research, sonar-reasoning |
|
|
243
|
+
| `--version` | `-v` | boolean | - | Show version |
|
|
244
|
+
| `--help` | `-h` | boolean | - | Show basic help |
|
|
245
|
+
|
|
246
|
+
### Advanced Options (Power Users)
|
|
132
247
|
|
|
133
248
|
| Option | Short | Type | Default | Description |
|
|
134
249
|
|--------|-------|------|---------|-------------|
|
|
135
|
-
| `--input` | `-
|
|
250
|
+
| `--input` | `-I` | string | - | Read batch requests from JSON file |
|
|
136
251
|
| `--stdin` | `-s` | boolean | false | Read JSONL requests from stdin |
|
|
137
252
|
| `--concurrency` | `-c` | number | 5 | Max concurrent requests (1-20) |
|
|
138
253
|
| `--timeout` | `-t` | number | 30000 | Request timeout in ms (1000-300000) |
|
|
139
|
-
| `--
|
|
140
|
-
| `--
|
|
141
|
-
| `--
|
|
142
|
-
| `--
|
|
254
|
+
| `--workspace` | `-w` | string | - | Workspace directory for sandboxing |
|
|
255
|
+
| `--attach` | - | string[] | - | Attach document files (multiple) |
|
|
256
|
+
| `--attach-image` | - | string[] | - | Attach image files (multiple) |
|
|
257
|
+
| `--async` | - | boolean | false | Process requests asynchronously |
|
|
258
|
+
| `--webhook` | - | string | - | Webhook URL for async notifications |
|
|
259
|
+
| `--help-advanced` | - | boolean | - | Show advanced help with all options |
|
|
260
|
+
|
|
261
|
+
### Quick Reference
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
# Basic usage (simplified)
|
|
265
|
+
pplx -f doc.pdf -m sonar-pro "analyze this"
|
|
266
|
+
|
|
267
|
+
# Advanced usage (full control)
|
|
268
|
+
pplx -I batch.json -c 10 -t 60000 --format jsonl "process all"
|
|
269
|
+
|
|
270
|
+
# See all available options
|
|
271
|
+
pplx --help-advanced
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### AI Models
|
|
275
|
+
|
|
276
|
+
- `sonar` - Fast, concise responses (default)
|
|
277
|
+
- `sonar-pro` - Detailed, comprehensive responses
|
|
278
|
+
- `sonar-deep-research` - In-depth research with web search
|
|
279
|
+
- `sonar-reasoning` - Step-by-step logical reasoning
|
|
143
280
|
|
|
144
|
-
##
|
|
281
|
+
## Output Formats
|
|
145
282
|
|
|
146
283
|
### JSON (Default)
|
|
147
284
|
```json
|
|
@@ -164,7 +301,7 @@ pplx --format jsonl "AI trends"
|
|
|
164
301
|
```
|
|
165
302
|
Each result printed as a separate JSON line for real-time processing.
|
|
166
303
|
|
|
167
|
-
##
|
|
304
|
+
## Development
|
|
168
305
|
|
|
169
306
|
```bash
|
|
170
307
|
# Development mode
|
|
@@ -183,15 +320,15 @@ bun run build
|
|
|
183
320
|
bun run build:binary
|
|
184
321
|
```
|
|
185
322
|
|
|
186
|
-
##
|
|
323
|
+
## Architecture
|
|
187
324
|
|
|
188
|
-
- **Bun Runtime** -
|
|
325
|
+
- **Bun Runtime** - Fast JavaScript runtime
|
|
189
326
|
- **Zod Validation** - Type-safe schema validation
|
|
190
|
-
- **
|
|
191
|
-
- **
|
|
327
|
+
- **Error Handling** - Resilient error recovery
|
|
328
|
+
- **Concurrency Control** - Semaphore pattern for rate limiting
|
|
192
329
|
- **Streaming Events** - Real-time progress updates
|
|
193
330
|
|
|
194
|
-
##
|
|
331
|
+
## Security Features
|
|
195
332
|
|
|
196
333
|
- Environment variable API key management
|
|
197
334
|
- Input validation and sanitization
|
|
@@ -199,7 +336,7 @@ bun run build:binary
|
|
|
199
336
|
- Error information filtering
|
|
200
337
|
- No external dependencies beyond core runtime
|
|
201
338
|
|
|
202
|
-
##
|
|
339
|
+
## Error Handling
|
|
203
340
|
|
|
204
341
|
PPLX-Zero provides comprehensive error classification:
|
|
205
342
|
|
|
@@ -215,14 +352,14 @@ enum ErrorCode {
|
|
|
215
352
|
}
|
|
216
353
|
```
|
|
217
354
|
|
|
218
|
-
##
|
|
355
|
+
## Contributing
|
|
219
356
|
|
|
220
357
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
221
358
|
|
|
222
|
-
##
|
|
359
|
+
## License
|
|
223
360
|
|
|
224
361
|
MIT License - see [LICENSE](LICENSE) file for details.
|
|
225
362
|
|
|
226
363
|
---
|
|
227
364
|
|
|
228
|
-
**Built with
|
|
365
|
+
**Built with [Bun](https://bun.sh) and [Perplexity AI](https://www.perplexity.ai)**
|
package/dist/cli.js
CHANGED
|
@@ -31,8 +31,8 @@ var __export = (target, all) => {
|
|
|
31
31
|
var require_package = __commonJS((exports, module) => {
|
|
32
32
|
module.exports = {
|
|
33
33
|
name: "pplx-zero",
|
|
34
|
-
version: "1.0.
|
|
35
|
-
description: "
|
|
34
|
+
version: "1.0.1",
|
|
35
|
+
description: "Fast Perplexity AI search CLI with multimodal support - minimal setup, maximal results",
|
|
36
36
|
type: "module",
|
|
37
37
|
main: "dist/index.js",
|
|
38
38
|
bin: {
|
|
@@ -80,10 +80,22 @@ var require_package = __commonJS((exports, module) => {
|
|
|
80
80
|
"minimal",
|
|
81
81
|
"fast",
|
|
82
82
|
"productivity",
|
|
83
|
-
"zero-config"
|
|
83
|
+
"zero-config",
|
|
84
|
+
"multimodal",
|
|
85
|
+
"attachments",
|
|
86
|
+
"images",
|
|
87
|
+
"documents",
|
|
88
|
+
"sonar",
|
|
89
|
+
"reasoning",
|
|
90
|
+
"research",
|
|
91
|
+
"async"
|
|
84
92
|
],
|
|
85
93
|
author: "Kenzo",
|
|
86
94
|
license: "MIT",
|
|
95
|
+
repository: {
|
|
96
|
+
type: "git",
|
|
97
|
+
url: "https://github.com/codewithkenzo/pplx-zero.git"
|
|
98
|
+
},
|
|
87
99
|
files: [
|
|
88
100
|
"dist",
|
|
89
101
|
"README.md",
|
|
@@ -5602,10 +5614,26 @@ Perplexity.Async = Async;
|
|
|
5602
5614
|
Perplexity.Search = Search;
|
|
5603
5615
|
// src/schema.ts
|
|
5604
5616
|
var SCHEMA_VERSION = "1.0.0";
|
|
5617
|
+
var SonarModelSchema = exports_external.enum(["sonar", "sonar-pro", "sonar-deep-research", "sonar-reasoning"]);
|
|
5618
|
+
var AttachmentSchema = exports_external.object({
|
|
5619
|
+
name: exports_external.string().min(1, "Attachment name is required"),
|
|
5620
|
+
extension: exports_external.string().min(1, "File extension is required"),
|
|
5621
|
+
mimeType: exports_external.string().min(1, "MIME type is required"),
|
|
5622
|
+
url: exports_external.string().min(1, "Attachment URL is required"),
|
|
5623
|
+
size: exports_external.number().int().min(0, "File size must be non-negative").optional()
|
|
5624
|
+
});
|
|
5625
|
+
var AttachmentInputSchema = exports_external.object({
|
|
5626
|
+
path: exports_external.string().min(1, "File path is required"),
|
|
5627
|
+
name: exports_external.string().optional(),
|
|
5628
|
+
type: exports_external.enum(["image", "document"]).optional()
|
|
5629
|
+
});
|
|
5605
5630
|
var SearchQuerySchema = exports_external.object({
|
|
5606
5631
|
query: exports_external.string().min(1, "Query cannot be empty"),
|
|
5607
5632
|
maxResults: exports_external.number().int().min(1).max(50).optional().default(5),
|
|
5608
|
-
country: exports_external.string().length(2).regex(/^[A-Z]{2}$/, "Invalid country code").optional()
|
|
5633
|
+
country: exports_external.string().length(2).regex(/^[A-Z]{2}$/, "Invalid country code").optional(),
|
|
5634
|
+
model: SonarModelSchema.optional().default("sonar"),
|
|
5635
|
+
attachments: exports_external.array(AttachmentSchema).optional(),
|
|
5636
|
+
attachmentInputs: exports_external.array(AttachmentInputSchema).optional()
|
|
5609
5637
|
});
|
|
5610
5638
|
var SearchInputV1Schema = exports_external.object({
|
|
5611
5639
|
id: exports_external.string().uuid().optional(),
|
|
@@ -5613,9 +5641,22 @@ var SearchInputV1Schema = exports_external.object({
|
|
|
5613
5641
|
args: SearchQuerySchema,
|
|
5614
5642
|
options: exports_external.object({
|
|
5615
5643
|
timeoutMs: exports_external.number().int().min(1000).max(300000).optional().default(30000),
|
|
5616
|
-
workspace: exports_external.string().optional()
|
|
5644
|
+
workspace: exports_external.string().optional(),
|
|
5645
|
+
async: exports_external.boolean().optional().default(false),
|
|
5646
|
+
webhook: exports_external.string().url().optional()
|
|
5617
5647
|
}).optional()
|
|
5618
5648
|
});
|
|
5649
|
+
var AsyncJobSchema = exports_external.object({
|
|
5650
|
+
id: exports_external.string(),
|
|
5651
|
+
model: SonarModelSchema,
|
|
5652
|
+
status: exports_external.enum(["CREATED", "IN_PROGRESS", "COMPLETED", "FAILED"]),
|
|
5653
|
+
createdAt: exports_external.number(),
|
|
5654
|
+
startedAt: exports_external.number().optional(),
|
|
5655
|
+
completedAt: exports_external.number().optional(),
|
|
5656
|
+
failedAt: exports_external.number().optional(),
|
|
5657
|
+
errorMessage: exports_external.string().optional(),
|
|
5658
|
+
response: exports_external.any().optional()
|
|
5659
|
+
});
|
|
5619
5660
|
var BatchSearchInputV1Schema = exports_external.object({
|
|
5620
5661
|
version: exports_external.string().regex(/^\d+\.\d+\.\d+$/).default(SCHEMA_VERSION),
|
|
5621
5662
|
requests: exports_external.array(SearchInputV1Schema).min(1).max(100),
|
|
@@ -6438,6 +6479,142 @@ function createLogger(context = {}) {
|
|
|
6438
6479
|
return new Logger(1 /* INFO */, context);
|
|
6439
6480
|
}
|
|
6440
6481
|
|
|
6482
|
+
// src/util/attachments.ts
|
|
6483
|
+
import { readFile, stat } from "node:fs/promises";
|
|
6484
|
+
import { extname, basename } from "node:path";
|
|
6485
|
+
var IMAGE_MIME_TYPES = {
|
|
6486
|
+
".png": "image/png",
|
|
6487
|
+
".jpg": "image/jpeg",
|
|
6488
|
+
".jpeg": "image/jpeg",
|
|
6489
|
+
".webp": "image/webp",
|
|
6490
|
+
".heif": "image/heif",
|
|
6491
|
+
".heic": "image/heic",
|
|
6492
|
+
".gif": "image/gif"
|
|
6493
|
+
};
|
|
6494
|
+
var DOCUMENT_MIME_TYPES = {
|
|
6495
|
+
".pdf": "application/pdf",
|
|
6496
|
+
".doc": "application/msword",
|
|
6497
|
+
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
6498
|
+
".txt": "text/plain",
|
|
6499
|
+
".rtf": "application/rtf"
|
|
6500
|
+
};
|
|
6501
|
+
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
6502
|
+
var MAX_ATTACHMENTS = 10;
|
|
6503
|
+
function isSupportedFileType(extension) {
|
|
6504
|
+
return extension.toLowerCase() in IMAGE_MIME_TYPES || extension.toLowerCase() in DOCUMENT_MIME_TYPES;
|
|
6505
|
+
}
|
|
6506
|
+
function isImageFile(extension) {
|
|
6507
|
+
return extension.toLowerCase() in IMAGE_MIME_TYPES;
|
|
6508
|
+
}
|
|
6509
|
+
function getMimeType(extension) {
|
|
6510
|
+
const ext = extension.toLowerCase();
|
|
6511
|
+
return IMAGE_MIME_TYPES[ext] || DOCUMENT_MIME_TYPES[ext] || null;
|
|
6512
|
+
}
|
|
6513
|
+
function calculateImageTokens(width, height) {
|
|
6514
|
+
return Math.ceil(width * height / 750);
|
|
6515
|
+
}
|
|
6516
|
+
async function getImageDimensions(filePath) {
|
|
6517
|
+
try {
|
|
6518
|
+
const buffer = await readFile(filePath);
|
|
6519
|
+
if (buffer.length < 24)
|
|
6520
|
+
return null;
|
|
6521
|
+
return { width: 1920, height: 1080 };
|
|
6522
|
+
} catch {
|
|
6523
|
+
return null;
|
|
6524
|
+
}
|
|
6525
|
+
}
|
|
6526
|
+
async function validateFile(filePath) {
|
|
6527
|
+
try {
|
|
6528
|
+
const stats = await stat(filePath);
|
|
6529
|
+
if (!stats.isFile()) {
|
|
6530
|
+
return { valid: false, error: "Path is not a file" };
|
|
6531
|
+
}
|
|
6532
|
+
if (stats.size > MAX_FILE_SIZE) {
|
|
6533
|
+
return {
|
|
6534
|
+
valid: false,
|
|
6535
|
+
error: `File size ${Math.round(stats.size / 1024 / 1024)}MB exceeds maximum ${MAX_FILE_SIZE / 1024 / 1024}MB`,
|
|
6536
|
+
size: stats.size
|
|
6537
|
+
};
|
|
6538
|
+
}
|
|
6539
|
+
return { valid: true, size: stats.size };
|
|
6540
|
+
} catch (error) {
|
|
6541
|
+
return {
|
|
6542
|
+
valid: false,
|
|
6543
|
+
error: `Cannot access file: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
6544
|
+
};
|
|
6545
|
+
}
|
|
6546
|
+
}
|
|
6547
|
+
async function processAttachment(input) {
|
|
6548
|
+
const filePath = input.path;
|
|
6549
|
+
const fileName = input.name || basename(filePath);
|
|
6550
|
+
const extension = extname(fileName);
|
|
6551
|
+
const mimeType = getMimeType(extension);
|
|
6552
|
+
if (!mimeType) {
|
|
6553
|
+
throw new Error(`Unsupported file type: ${extension}`);
|
|
6554
|
+
}
|
|
6555
|
+
const validation = await validateFile(filePath);
|
|
6556
|
+
if (!validation.valid) {
|
|
6557
|
+
throw new Error(validation.error || "File validation failed");
|
|
6558
|
+
}
|
|
6559
|
+
const fileContent = await readFile(filePath);
|
|
6560
|
+
const base64Content = fileContent.toString("base64");
|
|
6561
|
+
let url;
|
|
6562
|
+
if (isImageFile(extension)) {
|
|
6563
|
+
url = `data:${mimeType};base64,${base64Content}`;
|
|
6564
|
+
} else {
|
|
6565
|
+
url = base64Content;
|
|
6566
|
+
}
|
|
6567
|
+
let tokens;
|
|
6568
|
+
if (isImageFile(extension)) {
|
|
6569
|
+
const dimensions = await getImageDimensions(filePath);
|
|
6570
|
+
if (dimensions) {
|
|
6571
|
+
tokens = calculateImageTokens(dimensions.width, dimensions.height);
|
|
6572
|
+
}
|
|
6573
|
+
}
|
|
6574
|
+
return {
|
|
6575
|
+
name: fileName,
|
|
6576
|
+
extension,
|
|
6577
|
+
mimeType,
|
|
6578
|
+
url,
|
|
6579
|
+
size: validation.size
|
|
6580
|
+
};
|
|
6581
|
+
}
|
|
6582
|
+
async function processAttachments(inputs) {
|
|
6583
|
+
if (inputs.length > MAX_ATTACHMENTS) {
|
|
6584
|
+
throw new Error(`Maximum ${MAX_ATTACHMENTS} attachments allowed per request`);
|
|
6585
|
+
}
|
|
6586
|
+
const attachments = [];
|
|
6587
|
+
for (const input of inputs) {
|
|
6588
|
+
try {
|
|
6589
|
+
const attachment = await processAttachment(input);
|
|
6590
|
+
attachments.push(attachment);
|
|
6591
|
+
} catch (error) {
|
|
6592
|
+
throw new Error(`Failed to process attachment ${input.path}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
6593
|
+
}
|
|
6594
|
+
}
|
|
6595
|
+
return attachments;
|
|
6596
|
+
}
|
|
6597
|
+
function validateAttachmentInputs(inputs) {
|
|
6598
|
+
const errors2 = [];
|
|
6599
|
+
if (inputs.length > MAX_ATTACHMENTS) {
|
|
6600
|
+
errors2.push(`Maximum ${MAX_ATTACHMENTS} attachments allowed per request`);
|
|
6601
|
+
}
|
|
6602
|
+
for (const input of inputs) {
|
|
6603
|
+
if (!input.path) {
|
|
6604
|
+
errors2.push("Attachment path is required");
|
|
6605
|
+
continue;
|
|
6606
|
+
}
|
|
6607
|
+
const extension = extname(input.path).toLowerCase();
|
|
6608
|
+
if (!isSupportedFileType(extension)) {
|
|
6609
|
+
errors2.push(`Unsupported file type: ${extension} for ${input.path}`);
|
|
6610
|
+
}
|
|
6611
|
+
}
|
|
6612
|
+
return {
|
|
6613
|
+
valid: errors2.length === 0,
|
|
6614
|
+
errors: errors2
|
|
6615
|
+
};
|
|
6616
|
+
}
|
|
6617
|
+
|
|
6441
6618
|
// src/index.ts
|
|
6442
6619
|
class PerplexitySearchTool {
|
|
6443
6620
|
client;
|
|
@@ -6445,6 +6622,7 @@ class PerplexitySearchTool {
|
|
|
6445
6622
|
resilience;
|
|
6446
6623
|
logger;
|
|
6447
6624
|
metrics;
|
|
6625
|
+
defaultModel;
|
|
6448
6626
|
constructor(workspacePath, options = {}) {
|
|
6449
6627
|
const apiKey = process.env.PERPLEXITY_API_KEY || process.env.PERPLEXITY_AI_API_KEY;
|
|
6450
6628
|
if (!apiKey) {
|
|
@@ -6452,6 +6630,7 @@ class PerplexitySearchTool {
|
|
|
6452
6630
|
}
|
|
6453
6631
|
this.client = new Perplexity({ apiKey });
|
|
6454
6632
|
this.workspace = new WorkspaceSandbox(workspacePath);
|
|
6633
|
+
this.defaultModel = options.defaultModel || "sonar";
|
|
6455
6634
|
const resilienceConfig = options.resilienceProfile && options.resilienceProfile !== "custom" ? DEFAULT_CONFIGS[options.resilienceProfile] : options.resilienceConfig || DEFAULT_CONFIGS.balanced;
|
|
6456
6635
|
this.resilience = new ResilienceManager(resilienceConfig);
|
|
6457
6636
|
this.logger = createLogger({
|
|
@@ -6462,7 +6641,8 @@ class PerplexitySearchTool {
|
|
|
6462
6641
|
this.metrics = new MetricsCollector;
|
|
6463
6642
|
this.logger.info("PerplexitySearchTool initialized", {
|
|
6464
6643
|
workspace: workspacePath,
|
|
6465
|
-
resilienceProfile: options.resilienceProfile || "balanced"
|
|
6644
|
+
resilienceProfile: options.resilienceProfile || "balanced",
|
|
6645
|
+
defaultModel: this.defaultModel
|
|
6466
6646
|
});
|
|
6467
6647
|
}
|
|
6468
6648
|
async runTask(input, signal) {
|
|
@@ -6473,9 +6653,27 @@ class PerplexitySearchTool {
|
|
|
6473
6653
|
const validatedInput = SearchInputV1Schema.parse(input);
|
|
6474
6654
|
traceLogger.info("Starting search task", {
|
|
6475
6655
|
query: validatedInput.args.query,
|
|
6656
|
+
model: validatedInput.args.model || this.defaultModel,
|
|
6476
6657
|
maxResults: validatedInput.args.maxResults,
|
|
6477
|
-
country: validatedInput.args.country
|
|
6658
|
+
country: validatedInput.args.country,
|
|
6659
|
+
hasAttachments: validatedInput.args.attachments && validatedInput.args.attachments.length > 0,
|
|
6660
|
+
hasAttachmentInputs: validatedInput.args.attachmentInputs && validatedInput.args.attachmentInputs.length > 0,
|
|
6661
|
+
async: validatedInput.options?.async,
|
|
6662
|
+
webhook: validatedInput.options?.webhook
|
|
6478
6663
|
});
|
|
6664
|
+
let attachments = [];
|
|
6665
|
+
if (validatedInput.args.attachmentInputs && validatedInput.args.attachmentInputs.length > 0) {
|
|
6666
|
+
const validation = validateAttachmentInputs(validatedInput.args.attachmentInputs);
|
|
6667
|
+
if (!validation.valid) {
|
|
6668
|
+
throw new Error(`Attachment validation failed: ${validation.errors.join(", ")}`);
|
|
6669
|
+
}
|
|
6670
|
+
attachments = await processAttachments(validatedInput.args.attachmentInputs);
|
|
6671
|
+
} else if (validatedInput.args.attachments) {
|
|
6672
|
+
attachments = validatedInput.args.attachments;
|
|
6673
|
+
}
|
|
6674
|
+
if (validatedInput.args.attachments) {
|
|
6675
|
+
attachments = [...attachments, ...validatedInput.args.attachments];
|
|
6676
|
+
}
|
|
6479
6677
|
const timeoutMs = validatedInput.options?.timeoutMs || 30000;
|
|
6480
6678
|
const controller = new AbortController;
|
|
6481
6679
|
if (signal) {
|
|
@@ -6483,15 +6681,18 @@ class PerplexitySearchTool {
|
|
|
6483
6681
|
}
|
|
6484
6682
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
6485
6683
|
try {
|
|
6486
|
-
const { result, metrics: metrics2 } = await traceLogger.measure("search_operation", () => this.resilience.execute(() => this.
|
|
6684
|
+
const { result, metrics: metrics2 } = await traceLogger.measure("search_operation", () => this.resilience.execute(() => this.performChatCompletion(validatedInput.args, attachments, controller.signal)), {
|
|
6487
6685
|
query: validatedInput.args.query,
|
|
6686
|
+
model: validatedInput.args.model || this.defaultModel,
|
|
6488
6687
|
maxResults: validatedInput.args.maxResults,
|
|
6489
|
-
country: validatedInput.args.country
|
|
6688
|
+
country: validatedInput.args.country,
|
|
6689
|
+
attachmentCount: attachments.length
|
|
6490
6690
|
});
|
|
6491
6691
|
clearTimeout(timeoutId);
|
|
6492
6692
|
const duration = Date.now() - startTime;
|
|
6493
6693
|
this.metrics.recordMetric("search_duration", duration, "ms", {
|
|
6494
6694
|
query: validatedInput.args.query,
|
|
6695
|
+
model: validatedInput.args.model || this.defaultModel,
|
|
6495
6696
|
success: "true"
|
|
6496
6697
|
});
|
|
6497
6698
|
this.metrics.incrementCounter("search_requests_total", 1, { status: "success" });
|
|
@@ -6500,7 +6701,8 @@ class PerplexitySearchTool {
|
|
|
6500
6701
|
});
|
|
6501
6702
|
traceLogger.info("Search task completed successfully", {
|
|
6502
6703
|
resultCount: result.length,
|
|
6503
|
-
duration
|
|
6704
|
+
duration,
|
|
6705
|
+
model: validatedInput.args.model || this.defaultModel
|
|
6504
6706
|
});
|
|
6505
6707
|
return {
|
|
6506
6708
|
id,
|
|
@@ -6614,33 +6816,98 @@ class PerplexitySearchTool {
|
|
|
6614
6816
|
};
|
|
6615
6817
|
}
|
|
6616
6818
|
}
|
|
6617
|
-
async
|
|
6819
|
+
async performChatCompletion(query, attachments, signal) {
|
|
6618
6820
|
try {
|
|
6619
|
-
const
|
|
6620
|
-
|
|
6621
|
-
|
|
6821
|
+
const messages = [
|
|
6822
|
+
{
|
|
6823
|
+
role: "system",
|
|
6824
|
+
content: "You are a helpful AI assistant. Provide accurate, concise responses with citations when possible."
|
|
6825
|
+
}
|
|
6826
|
+
];
|
|
6827
|
+
const userMessage = {
|
|
6828
|
+
role: "user",
|
|
6829
|
+
content: [
|
|
6830
|
+
{ type: "text", text: query.query }
|
|
6831
|
+
]
|
|
6622
6832
|
};
|
|
6623
|
-
if (
|
|
6624
|
-
|
|
6833
|
+
if (attachments.length > 0) {
|
|
6834
|
+
for (const attachment of attachments) {
|
|
6835
|
+
if (attachment.mimeType.startsWith("image/")) {
|
|
6836
|
+
userMessage.content.push({
|
|
6837
|
+
type: "image_url",
|
|
6838
|
+
image_url: {
|
|
6839
|
+
url: attachment.url
|
|
6840
|
+
}
|
|
6841
|
+
});
|
|
6842
|
+
} else {
|
|
6843
|
+
userMessage.content.push({
|
|
6844
|
+
type: "file_url",
|
|
6845
|
+
file_url: {
|
|
6846
|
+
url: attachment.url
|
|
6847
|
+
},
|
|
6848
|
+
file_name: attachment.name
|
|
6849
|
+
});
|
|
6850
|
+
}
|
|
6851
|
+
}
|
|
6625
6852
|
}
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
}
|
|
6853
|
+
messages.push(userMessage);
|
|
6854
|
+
const chatParams = {
|
|
6855
|
+
model: query.model || this.defaultModel,
|
|
6856
|
+
messages,
|
|
6857
|
+
max_tokens: 4000,
|
|
6858
|
+
temperature: 0.1,
|
|
6859
|
+
top_p: 0.9,
|
|
6860
|
+
search_domain_filter: query.country ? [`.${query.country.toLowerCase()}`] : undefined,
|
|
6861
|
+
return_images: false,
|
|
6862
|
+
return_related_questions: false,
|
|
6863
|
+
search_recency_filter: undefined,
|
|
6864
|
+
search_after_date_filter: undefined,
|
|
6865
|
+
search_before_date_filter: undefined,
|
|
6866
|
+
last_updated_after_filter: undefined,
|
|
6867
|
+
last_updated_before_filter: undefined,
|
|
6868
|
+
top_k: 0,
|
|
6869
|
+
stream: false,
|
|
6870
|
+
presence_penalty: 0,
|
|
6871
|
+
frequency_penalty: 0,
|
|
6872
|
+
disable_search: false,
|
|
6873
|
+
enable_search_classifier: false,
|
|
6874
|
+
web_search_options: {
|
|
6875
|
+
search_context_size: "high"
|
|
6876
|
+
}
|
|
6877
|
+
};
|
|
6878
|
+
const response = await this.client.chat.completions.create(chatParams);
|
|
6879
|
+
if (response.choices && response.choices.length > 0) {
|
|
6880
|
+
const choice = response.choices[0];
|
|
6881
|
+
const content = choice.message?.content || "";
|
|
6882
|
+
const results = [];
|
|
6883
|
+
results.push({
|
|
6884
|
+
title: "AI Response",
|
|
6885
|
+
url: "https://www.perplexity.ai/",
|
|
6886
|
+
snippet: content,
|
|
6887
|
+
date: new Date().toISOString().split("T")[0]
|
|
6888
|
+
});
|
|
6889
|
+
if (response.search_results && Array.isArray(response.search_results)) {
|
|
6890
|
+
response.search_results.forEach((result) => {
|
|
6891
|
+
results.push({
|
|
6892
|
+
title: result.title || "Search Result",
|
|
6893
|
+
url: result.url || "",
|
|
6894
|
+
snippet: result.snippet || "",
|
|
6895
|
+
date: result.date || undefined
|
|
6896
|
+
});
|
|
6897
|
+
});
|
|
6898
|
+
}
|
|
6899
|
+
const maxResults = query.maxResults || 5;
|
|
6900
|
+
return results.slice(0, maxResults);
|
|
6634
6901
|
}
|
|
6635
6902
|
return [{
|
|
6636
|
-
title: "
|
|
6903
|
+
title: "No Response",
|
|
6637
6904
|
url: "https://www.perplexity.ai/",
|
|
6638
|
-
snippet: "No
|
|
6905
|
+
snippet: "No response received from the model",
|
|
6639
6906
|
date: undefined
|
|
6640
6907
|
}];
|
|
6641
6908
|
} catch (error) {
|
|
6642
6909
|
if (error instanceof Error && error.name === "AbortError") {
|
|
6643
|
-
throw new Error("
|
|
6910
|
+
throw new Error("Chat completion request timed out");
|
|
6644
6911
|
}
|
|
6645
6912
|
throw error instanceof Error ? error : new Error(String(error));
|
|
6646
6913
|
}
|
|
@@ -6723,34 +6990,59 @@ var { values: cliOptions, positionals: commandLineQueries } = parseArgs({
|
|
|
6723
6990
|
timeout: { type: "string", short: "t" },
|
|
6724
6991
|
workspace: { type: "string", short: "w" },
|
|
6725
6992
|
format: { type: "string", short: "f", default: "json" },
|
|
6726
|
-
"dry-run": { type: "boolean", short: "d" },
|
|
6727
6993
|
version: { type: "boolean", short: "v" },
|
|
6728
|
-
help: { type: "boolean", short: "h" }
|
|
6994
|
+
help: { type: "boolean", short: "h" },
|
|
6995
|
+
model: { type: "string", short: "m" },
|
|
6996
|
+
attach: { type: "string", multiple: true },
|
|
6997
|
+
"attach-image": { type: "string", multiple: true },
|
|
6998
|
+
async: { type: "boolean" },
|
|
6999
|
+
webhook: { type: "string" }
|
|
6729
7000
|
},
|
|
6730
7001
|
allowPositionals: true
|
|
6731
7002
|
});
|
|
6732
7003
|
if (cliOptions.help) {
|
|
6733
7004
|
console.error(`
|
|
6734
|
-
PPLX-Zero - Minimal, fast Perplexity AI search CLI
|
|
7005
|
+
PPLX-Zero - Minimal, fast Perplexity AI search CLI with multimodal support
|
|
6735
7006
|
|
|
6736
7007
|
USAGE:
|
|
6737
7008
|
pplx [OPTIONS] [QUERY...]
|
|
6738
7009
|
|
|
6739
7010
|
OPTIONS:
|
|
6740
|
-
-i, --input <file>
|
|
6741
|
-
-s, --stdin
|
|
6742
|
-
-c, --concurrency <n>
|
|
6743
|
-
-t, --timeout <ms>
|
|
6744
|
-
-w, --workspace <path>
|
|
6745
|
-
-f, --format <format>
|
|
6746
|
-
-
|
|
6747
|
-
|
|
6748
|
-
-
|
|
7011
|
+
-i, --input <file> Read batch requests from JSON file
|
|
7012
|
+
-s, --stdin Read JSONL requests from stdin
|
|
7013
|
+
-c, --concurrency <n> Max concurrent requests (default: 5)
|
|
7014
|
+
-t, --timeout <ms> Request timeout in milliseconds (default: 30000)
|
|
7015
|
+
-w, --workspace <path> Workspace directory for sandboxing
|
|
7016
|
+
-f, --format <format> Output format: json|jsonl (default: json)
|
|
7017
|
+
-m, --model <model> AI model: sonar, sonar-pro, sonar-deep-research, sonar-reasoning (default: sonar)
|
|
7018
|
+
--attach <file> Attach document files (PDF, DOC, DOCX, TXT, RTF) - can be used multiple times
|
|
7019
|
+
--attach-image <file> Attach image files (PNG, JPEG, WebP, HEIF, HEIC, GIF) - can be used multiple times
|
|
7020
|
+
--async Process requests asynchronously
|
|
7021
|
+
--webhook <url> Webhook URL for async notifications
|
|
7022
|
+
-v, --version Show version
|
|
7023
|
+
-h, --help Show this help
|
|
6749
7024
|
|
|
6750
7025
|
EXAMPLES:
|
|
6751
|
-
#
|
|
7026
|
+
# Basic query
|
|
6752
7027
|
pplx "latest AI developments"
|
|
6753
7028
|
|
|
7029
|
+
# Model selection
|
|
7030
|
+
pplx --model sonar-pro "Detailed analysis"
|
|
7031
|
+
pplx --model sonar-deep-research "Comprehensive research"
|
|
7032
|
+
pplx --model sonar-reasoning "Complex problem solving"
|
|
7033
|
+
|
|
7034
|
+
# Image analysis
|
|
7035
|
+
pplx --attach-image screenshot.png --model sonar-pro "Analyze this interface"
|
|
7036
|
+
|
|
7037
|
+
# Document analysis
|
|
7038
|
+
pplx --attach report.pdf --model sonar-deep-research "Summarize this document"
|
|
7039
|
+
|
|
7040
|
+
# Multimodal analysis
|
|
7041
|
+
pplx --attach document.txt --attach-image chart.png --model sonar-reasoning "Analyze this data"
|
|
7042
|
+
|
|
7043
|
+
# Async processing with webhook
|
|
7044
|
+
pplx --async --webhook https://api.example.com/callback "Long research task"
|
|
7045
|
+
|
|
6754
7046
|
# Batch from file
|
|
6755
7047
|
pplx --input queries.json
|
|
6756
7048
|
|
|
@@ -6760,8 +7052,12 @@ EXAMPLES:
|
|
|
6760
7052
|
# JSONL output for streaming
|
|
6761
7053
|
pplx --format jsonl --input queries.json
|
|
6762
7054
|
|
|
6763
|
-
# High concurrency batch
|
|
6764
|
-
pplx --concurrency 10 --timeout 60000 --input queries.json
|
|
7055
|
+
# High concurrency batch with attachments
|
|
7056
|
+
pplx --concurrency 10 --timeout 60000 --input queries.json --attach appendix.pdf
|
|
7057
|
+
|
|
7058
|
+
SUPPORTED FORMATS:
|
|
7059
|
+
Images: PNG, JPEG, WebP, HEIF, HEIC, GIF (max 50MB, 10 files)
|
|
7060
|
+
Documents: PDF, DOC, DOCX, TXT, RTF (max 50MB, 10 files)
|
|
6765
7061
|
`);
|
|
6766
7062
|
process.exit(0);
|
|
6767
7063
|
}
|
|
@@ -6842,11 +7138,20 @@ async function main() {
|
|
|
6842
7138
|
const requestTimeout = parseNumericArgument(cliOptions.timeout, DEFAULT_TIMEOUT, MIN_TIMEOUT, MAX_TIMEOUT, "Timeout");
|
|
6843
7139
|
const workspaceDirectory = cliOptions.workspace;
|
|
6844
7140
|
const outputFormat = cliOptions.format;
|
|
6845
|
-
const isDryRunMode = cliOptions["dry-run"];
|
|
6846
7141
|
if (!["json", "jsonl"].includes(outputFormat)) {
|
|
6847
7142
|
throw new Error("Format must be json or jsonl");
|
|
6848
7143
|
}
|
|
6849
|
-
|
|
7144
|
+
let selectedModel;
|
|
7145
|
+
if (cliOptions.model) {
|
|
7146
|
+
const validModels = ["sonar", "sonar-pro", "sonar-deep-research", "sonar-reasoning"];
|
|
7147
|
+
if (!validModels.includes(cliOptions.model)) {
|
|
7148
|
+
throw new Error(`Invalid model: ${cliOptions.model}. Valid models: ${validModels.join(", ")}`);
|
|
7149
|
+
}
|
|
7150
|
+
selectedModel = cliOptions.model;
|
|
7151
|
+
}
|
|
7152
|
+
const searchTool = new PerplexitySearchTool(workspaceDirectory, {
|
|
7153
|
+
defaultModel: selectedModel
|
|
7154
|
+
});
|
|
6850
7155
|
logEvent({
|
|
6851
7156
|
time: new Date().toISOString(),
|
|
6852
7157
|
level: "info",
|
|
@@ -6856,7 +7161,10 @@ async function main() {
|
|
|
6856
7161
|
timeout: requestTimeout,
|
|
6857
7162
|
workspace: workspaceDirectory,
|
|
6858
7163
|
format: outputFormat,
|
|
6859
|
-
|
|
7164
|
+
model: selectedModel,
|
|
7165
|
+
async: cliOptions.async,
|
|
7166
|
+
webhook: cliOptions.webhook,
|
|
7167
|
+
hasAttachments: (cliOptions.attach?.length || 0) + (cliOptions["attach-image"]?.length || 0) > 0
|
|
6860
7168
|
}
|
|
6861
7169
|
});
|
|
6862
7170
|
let batchSearchInput;
|
|
@@ -6869,13 +7177,37 @@ async function main() {
|
|
|
6869
7177
|
inputSourceType = cliOptions.input;
|
|
6870
7178
|
} else if (commandLineQueries.length > 0) {
|
|
6871
7179
|
const combinedQuery = commandLineQueries.join(" ");
|
|
7180
|
+
const attachmentInputs = [];
|
|
7181
|
+
if (cliOptions.attach && cliOptions.attach.length > 0) {
|
|
7182
|
+
for (const filePath of cliOptions.attach) {
|
|
7183
|
+
attachmentInputs.push({
|
|
7184
|
+
path: filePath,
|
|
7185
|
+
type: "document"
|
|
7186
|
+
});
|
|
7187
|
+
}
|
|
7188
|
+
}
|
|
7189
|
+
if (cliOptions["attach-image"] && cliOptions["attach-image"].length > 0) {
|
|
7190
|
+
for (const filePath of cliOptions["attach-image"]) {
|
|
7191
|
+
attachmentInputs.push({
|
|
7192
|
+
path: filePath,
|
|
7193
|
+
type: "image"
|
|
7194
|
+
});
|
|
7195
|
+
}
|
|
7196
|
+
}
|
|
6872
7197
|
batchSearchInput = {
|
|
6873
7198
|
version: "1.0.0",
|
|
6874
7199
|
requests: [{
|
|
6875
7200
|
op: "search",
|
|
6876
7201
|
args: {
|
|
6877
7202
|
query: combinedQuery,
|
|
6878
|
-
maxResults: 5
|
|
7203
|
+
maxResults: 5,
|
|
7204
|
+
model: selectedModel,
|
|
7205
|
+
attachmentInputs: attachmentInputs.length > 0 ? attachmentInputs : undefined
|
|
7206
|
+
},
|
|
7207
|
+
options: {
|
|
7208
|
+
timeoutMs: requestTimeout,
|
|
7209
|
+
async: cliOptions.async,
|
|
7210
|
+
webhook: cliOptions.webhook
|
|
6879
7211
|
}
|
|
6880
7212
|
}]
|
|
6881
7213
|
};
|
|
@@ -6899,21 +7231,6 @@ async function main() {
|
|
|
6899
7231
|
failFast: false,
|
|
6900
7232
|
...batchSearchInput.options
|
|
6901
7233
|
};
|
|
6902
|
-
if (isDryRunMode) {
|
|
6903
|
-
logEvent({
|
|
6904
|
-
time: new Date().toISOString(),
|
|
6905
|
-
level: "info",
|
|
6906
|
-
event: "dry_run_completed",
|
|
6907
|
-
data: { requestCount: batchSearchInput.requests?.length || 1 }
|
|
6908
|
-
});
|
|
6909
|
-
console.log(JSON.stringify({
|
|
6910
|
-
ok: true,
|
|
6911
|
-
message: "Dry run completed - input validation passed",
|
|
6912
|
-
requestCount: batchSearchInput.requests?.length || 1,
|
|
6913
|
-
inputSource: inputSourceType
|
|
6914
|
-
}, null, 2));
|
|
6915
|
-
return;
|
|
6916
|
-
}
|
|
6917
7234
|
logEvent({
|
|
6918
7235
|
time: new Date().toISOString(),
|
|
6919
7236
|
level: "info",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pplx-zero",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Fast Perplexity AI search CLI with multimodal support - minimal setup, maximal results",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
@@ -49,10 +49,22 @@
|
|
|
49
49
|
"minimal",
|
|
50
50
|
"fast",
|
|
51
51
|
"productivity",
|
|
52
|
-
"zero-config"
|
|
52
|
+
"zero-config",
|
|
53
|
+
"multimodal",
|
|
54
|
+
"attachments",
|
|
55
|
+
"images",
|
|
56
|
+
"documents",
|
|
57
|
+
"sonar",
|
|
58
|
+
"reasoning",
|
|
59
|
+
"research",
|
|
60
|
+
"async"
|
|
53
61
|
],
|
|
54
62
|
"author": "Kenzo",
|
|
55
63
|
"license": "MIT",
|
|
64
|
+
"repository": {
|
|
65
|
+
"type": "git",
|
|
66
|
+
"url": "git+https://github.com/codewithkenzo/pplx-zero.git"
|
|
67
|
+
},
|
|
56
68
|
"files": [
|
|
57
69
|
"dist",
|
|
58
70
|
"README.md",
|