@ducci/jarvis 1.0.19 → 1.0.21
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/package.json +1 -1
- package/src/scripts/onboarding.js +38 -0
- package/src/server/tools.js +66 -1
package/package.json
CHANGED
|
@@ -300,6 +300,44 @@ async function run() {
|
|
|
300
300
|
}
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
+
// --- PERPLEXITY STEP (OPTIONAL) ---
|
|
304
|
+
const existingPerplexityKey = loadEnvVar('PERPLEXITY_API_KEY');
|
|
305
|
+
const { configurePerplexity } = await inquirer.prompt([
|
|
306
|
+
{
|
|
307
|
+
type: 'confirm',
|
|
308
|
+
name: 'configurePerplexity',
|
|
309
|
+
message: 'Do you want to configure Perplexity web search?',
|
|
310
|
+
default: !!existingPerplexityKey
|
|
311
|
+
}
|
|
312
|
+
]);
|
|
313
|
+
|
|
314
|
+
if (configurePerplexity) {
|
|
315
|
+
let keepPerplexityKey = false;
|
|
316
|
+
if (existingPerplexityKey) {
|
|
317
|
+
const { keep } = await inquirer.prompt([
|
|
318
|
+
{
|
|
319
|
+
type: 'confirm',
|
|
320
|
+
name: 'keep',
|
|
321
|
+
message: 'A PERPLEXITY_API_KEY is already configured. Do you want to keep it?',
|
|
322
|
+
default: true
|
|
323
|
+
}
|
|
324
|
+
]);
|
|
325
|
+
keepPerplexityKey = keep;
|
|
326
|
+
}
|
|
327
|
+
if (!keepPerplexityKey) {
|
|
328
|
+
const { perplexityKey } = await inquirer.prompt([
|
|
329
|
+
{
|
|
330
|
+
type: 'password',
|
|
331
|
+
name: 'perplexityKey',
|
|
332
|
+
message: 'Enter your Perplexity API key (from perplexity.ai/settings/api):',
|
|
333
|
+
validate: (input) => input.trim().length > 0 || 'API key cannot be empty.'
|
|
334
|
+
}
|
|
335
|
+
]);
|
|
336
|
+
saveEnvVar('PERPLEXITY_API_KEY', perplexityKey.trim());
|
|
337
|
+
console.log(chalk.green('Perplexity API key saved.'));
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
303
341
|
console.log(chalk.green.bold('\nSetup complete!'));
|
|
304
342
|
}
|
|
305
343
|
|
package/src/server/tools.js
CHANGED
|
@@ -124,7 +124,7 @@ const SEED_TOOLS = {
|
|
|
124
124
|
type: 'function',
|
|
125
125
|
function: {
|
|
126
126
|
name: 'save_tool',
|
|
127
|
-
description: 'Create or update a custom tool and make it available immediately in this session. Use this to build reusable JS tools for tasks you repeat. The tool code runs in Node.js and has access to: args, fs, path, process, require, __jarvisDir.',
|
|
127
|
+
description: 'Create or update a custom tool and make it available immediately in this session. Use this to build reusable JS tools for tasks you repeat. The tool code runs in Node.js and has access to: args, fs, path, process, require, __jarvisDir. To update an existing tool, first call get_tool to read its current code and parameters, then call save_tool with your modifications.',
|
|
128
128
|
parameters: {
|
|
129
129
|
type: 'object',
|
|
130
130
|
properties: {
|
|
@@ -151,6 +151,26 @@ const SEED_TOOLS = {
|
|
|
151
151
|
},
|
|
152
152
|
code: `const toolsFile = path.join(process.env.HOME, '.jarvis/data/tools/tools.json'); const raw = await fs.promises.readFile(toolsFile, 'utf8').catch(() => '{}'); const tools = JSON.parse(raw); tools[args.name] = { definition: { type: 'function', function: { name: args.name, description: args.description, parameters: args.parameters } }, code: args.code }; await fs.promises.writeFile(toolsFile, JSON.stringify(tools, null, 2), 'utf8'); return { status: 'ok', saved: args.name };`,
|
|
153
153
|
},
|
|
154
|
+
get_tool: {
|
|
155
|
+
definition: {
|
|
156
|
+
type: 'function',
|
|
157
|
+
function: {
|
|
158
|
+
name: 'get_tool',
|
|
159
|
+
description: 'Read the full definition and code of a single tool by name. Use this before updating an existing tool so you understand its current implementation.',
|
|
160
|
+
parameters: {
|
|
161
|
+
type: 'object',
|
|
162
|
+
properties: {
|
|
163
|
+
name: {
|
|
164
|
+
type: 'string',
|
|
165
|
+
description: 'The tool name to retrieve.',
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
required: ['name'],
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
code: `const toolsFile = path.join(process.env.HOME, '.jarvis/data/tools/tools.json'); const raw = await fs.promises.readFile(toolsFile, 'utf8').catch(() => '{}'); const tools = JSON.parse(raw); const tool = tools[args.name]; if (!tool) return { status: 'not_found', name: args.name }; return { status: 'ok', name: args.name, definition: tool.definition, code: tool.code };`,
|
|
173
|
+
},
|
|
154
174
|
list_tools: {
|
|
155
175
|
definition: {
|
|
156
176
|
type: 'function',
|
|
@@ -201,6 +221,51 @@ const SEED_TOOLS = {
|
|
|
201
221
|
}
|
|
202
222
|
`,
|
|
203
223
|
},
|
|
224
|
+
perplexity_search: {
|
|
225
|
+
definition: {
|
|
226
|
+
type: 'function',
|
|
227
|
+
function: {
|
|
228
|
+
name: 'perplexity_search',
|
|
229
|
+
description: 'Search the web using Perplexity AI. Returns an answer grounded in real-time web results with citations. Use this for current events, factual lookups, or research questions.',
|
|
230
|
+
parameters: {
|
|
231
|
+
type: 'object',
|
|
232
|
+
properties: {
|
|
233
|
+
query: {
|
|
234
|
+
type: 'string',
|
|
235
|
+
description: 'The search query or question.',
|
|
236
|
+
},
|
|
237
|
+
model: {
|
|
238
|
+
type: 'string',
|
|
239
|
+
enum: ['sonar', 'sonar-pro', 'sonar-deep-research'],
|
|
240
|
+
description: 'Search model to use. sonar: fast and cheap, good for simple lookups. sonar-pro: deeper multi-step search, more citations, better for complex questions. sonar-deep-research: long-form research reports. Defaults to sonar.',
|
|
241
|
+
},
|
|
242
|
+
search_recency_filter: {
|
|
243
|
+
type: 'string',
|
|
244
|
+
enum: ['hour', 'day', 'week', 'month', 'year'],
|
|
245
|
+
description: 'Optional time filter to restrict results to recent content.',
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
required: ['query'],
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
code: `
|
|
253
|
+
const OpenAI = require('openai');
|
|
254
|
+
const client = new OpenAI({
|
|
255
|
+
apiKey: process.env.PERPLEXITY_API_KEY,
|
|
256
|
+
baseURL: 'https://api.perplexity.ai',
|
|
257
|
+
});
|
|
258
|
+
const params = {
|
|
259
|
+
model: args.model || 'sonar',
|
|
260
|
+
messages: [{ role: 'user', content: args.query }],
|
|
261
|
+
};
|
|
262
|
+
if (args.search_recency_filter) params.search_recency_filter = args.search_recency_filter;
|
|
263
|
+
const response = await client.chat.completions.create(params);
|
|
264
|
+
const answer = response.choices[0].message.content;
|
|
265
|
+
const citations = response.citations || [];
|
|
266
|
+
return { answer, citations };
|
|
267
|
+
`,
|
|
268
|
+
},
|
|
204
269
|
get_recent_sessions: {
|
|
205
270
|
definition: {
|
|
206
271
|
type: 'function',
|