@ducci/jarvis 1.0.18 → 1.0.20
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/docs/system-prompt.md +8 -0
- package/package.json +1 -1
- package/src/server/tools.js +61 -4
package/docs/system-prompt.md
CHANGED
|
@@ -53,6 +53,14 @@ The `exec` tool runs real shell commands on the server. Use it responsibly:
|
|
|
53
53
|
- **Prefer targeted reads.** Use `grep`, `head`, or `tail` instead of `cat` on files you haven't seen before. Large file output is truncated anyway — a targeted command gives you better signal.
|
|
54
54
|
- **Avoid commands with unbounded runtime.** If a command could run indefinitely or scan an unknown-size tree, scope it first.
|
|
55
55
|
|
|
56
|
+
## Tool Creation
|
|
57
|
+
|
|
58
|
+
When building a custom tool with `save_tool`:
|
|
59
|
+
|
|
60
|
+
- **Prefer npm packages** over reimplementing functionality from scratch. If a well-known package exists for the task (e.g. an API SDK, a parser, a utility library), use it.
|
|
61
|
+
- **Installing an npm package**: use the `npm_install` tool — it handles the correct install directory automatically. Then create the tool with `save_tool`. The tool code can `require('<package-name>')` directly.
|
|
62
|
+
- **Available bindings in tool code**: `args`, `fs`, `path`, `process`, `require`, `__jarvisDir` (absolute path to the jarvis server directory).
|
|
63
|
+
|
|
56
64
|
## logSummary Guidelines
|
|
57
65
|
|
|
58
66
|
The `logSummary` is written for a human observer, not for the user. It must:
|
package/package.json
CHANGED
package/src/server/tools.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
3
|
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
4
5
|
import { PATHS } from './config.js';
|
|
5
6
|
|
|
6
7
|
const _require = createRequire(import.meta.url);
|
|
8
|
+
const __jarvisDir = path.dirname(fileURLToPath(import.meta.url));
|
|
7
9
|
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
|
|
8
10
|
|
|
9
11
|
const TOOL_TIMEOUT_MS = 60_000;
|
|
@@ -122,7 +124,7 @@ const SEED_TOOLS = {
|
|
|
122
124
|
type: 'function',
|
|
123
125
|
function: {
|
|
124
126
|
name: 'save_tool',
|
|
125
|
-
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.',
|
|
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.',
|
|
126
128
|
parameters: {
|
|
127
129
|
type: 'object',
|
|
128
130
|
properties: {
|
|
@@ -140,7 +142,7 @@ const SEED_TOOLS = {
|
|
|
140
142
|
},
|
|
141
143
|
code: {
|
|
142
144
|
type: 'string',
|
|
143
|
-
description: 'The body of an async function. Must end with a return statement — the returned value becomes the tool result. Available bindings: args (your tool parameters), fs (node:fs), path (node:path), process, require. Do NOT wrap in a function declaration. Example: const raw = await fs.promises.readFile(args.filePath, "utf8"); const data = JSON.parse(raw); return { count: data.length, first: data[0] };',
|
|
145
|
+
description: 'The body of an async function. Must end with a return statement — the returned value becomes the tool result. Available bindings: args (your tool parameters), fs (node:fs), path (node:path), process, require, __jarvisDir (absolute path to the jarvis server directory — use path.resolve(__jarvisDir, "../..") to get the project root for npm installs). Do NOT wrap in a function declaration. Example: const raw = await fs.promises.readFile(args.filePath, "utf8"); const data = JSON.parse(raw); return { count: data.length, first: data[0] };',
|
|
144
146
|
},
|
|
145
147
|
},
|
|
146
148
|
required: ['name', 'description', 'parameters', 'code'],
|
|
@@ -149,6 +151,26 @@ const SEED_TOOLS = {
|
|
|
149
151
|
},
|
|
150
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 };`,
|
|
151
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
|
+
},
|
|
152
174
|
list_tools: {
|
|
153
175
|
definition: {
|
|
154
176
|
type: 'function',
|
|
@@ -164,6 +186,41 @@ const SEED_TOOLS = {
|
|
|
164
186
|
},
|
|
165
187
|
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 list = Object.entries(tools).map(([name, t]) => ({ name, description: t.definition.function.description })); return { status: 'ok', tools: list };`,
|
|
166
188
|
},
|
|
189
|
+
npm_install: {
|
|
190
|
+
definition: {
|
|
191
|
+
type: 'function',
|
|
192
|
+
function: {
|
|
193
|
+
name: 'npm_install',
|
|
194
|
+
description: 'Install an npm package into the jarvis project so it can be used in tool code via require(). Always use this instead of exec to install packages.',
|
|
195
|
+
parameters: {
|
|
196
|
+
type: 'object',
|
|
197
|
+
properties: {
|
|
198
|
+
packageName: {
|
|
199
|
+
type: 'string',
|
|
200
|
+
description: 'The npm package name to install, e.g. "@perplexity-ai/sdk" or "axios".',
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
required: ['packageName'],
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
code: `
|
|
208
|
+
const { exec } = require('child_process');
|
|
209
|
+
const { promisify } = require('util');
|
|
210
|
+
const execAsync = promisify(exec);
|
|
211
|
+
const projectRoot = path.resolve(__jarvisDir, '../..');
|
|
212
|
+
try {
|
|
213
|
+
const { stdout, stderr } = await execAsync('npm install ' + args.packageName, {
|
|
214
|
+
cwd: projectRoot,
|
|
215
|
+
encoding: 'utf8',
|
|
216
|
+
timeout: 60000,
|
|
217
|
+
});
|
|
218
|
+
return { status: 'ok', packageName: args.packageName, stdout, stderr };
|
|
219
|
+
} catch (e) {
|
|
220
|
+
return { status: 'error', packageName: args.packageName, stderr: e.stderr || e.message };
|
|
221
|
+
}
|
|
222
|
+
`,
|
|
223
|
+
},
|
|
167
224
|
get_recent_sessions: {
|
|
168
225
|
definition: {
|
|
169
226
|
type: 'function',
|
|
@@ -255,7 +312,7 @@ export async function executeTool(tools, name, toolArgs) {
|
|
|
255
312
|
throw new Error(`Unknown tool: ${name}`);
|
|
256
313
|
}
|
|
257
314
|
|
|
258
|
-
const fn = new AsyncFunction('args', 'fs', 'path', 'process', 'require', tool.code);
|
|
315
|
+
const fn = new AsyncFunction('args', 'fs', 'path', 'process', 'require', '__jarvisDir', tool.code);
|
|
259
316
|
|
|
260
317
|
const timeout = new Promise((_, reject) =>
|
|
261
318
|
setTimeout(
|
|
@@ -264,5 +321,5 @@ export async function executeTool(tools, name, toolArgs) {
|
|
|
264
321
|
)
|
|
265
322
|
);
|
|
266
323
|
|
|
267
|
-
return await Promise.race([fn(toolArgs, fs, path, process, _require), timeout]);
|
|
324
|
+
return await Promise.race([fn(toolArgs, fs, path, process, _require, __jarvisDir), timeout]);
|
|
268
325
|
}
|