@ducci/jarvis 1.0.43 → 1.0.45
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/server/tools.js +43 -66
package/package.json
CHANGED
package/src/server/tools.js
CHANGED
|
@@ -11,35 +11,40 @@ const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
|
|
|
11
11
|
const TOOL_TIMEOUT_MS = 60_000;
|
|
12
12
|
|
|
13
13
|
const SEED_TOOLS = {
|
|
14
|
-
|
|
14
|
+
read_file: {
|
|
15
15
|
definition: {
|
|
16
16
|
type: 'function',
|
|
17
17
|
function: {
|
|
18
|
-
name: '
|
|
19
|
-
description: '
|
|
18
|
+
name: 'read_file',
|
|
19
|
+
description: 'Read a file from disk. Returns the file content as a string. Use offset and limit to read large files in chunks instead of loading everything at once.',
|
|
20
20
|
parameters: {
|
|
21
21
|
type: 'object',
|
|
22
22
|
properties: {
|
|
23
23
|
path: {
|
|
24
24
|
type: 'string',
|
|
25
|
-
description: '
|
|
25
|
+
description: 'Absolute or relative path to the file to read.',
|
|
26
|
+
},
|
|
27
|
+
offset: {
|
|
28
|
+
type: 'number',
|
|
29
|
+
description: 'Line number to start reading from (1-based). Omit to start from the beginning.',
|
|
30
|
+
},
|
|
31
|
+
limit: {
|
|
32
|
+
type: 'number',
|
|
33
|
+
description: 'Maximum number of lines to return. Omit to read the entire file (or remainder from offset).',
|
|
26
34
|
},
|
|
27
35
|
},
|
|
28
|
-
required: [],
|
|
36
|
+
required: ['path'],
|
|
29
37
|
},
|
|
30
38
|
},
|
|
31
39
|
},
|
|
32
40
|
code: `
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
timeout: 10000,
|
|
41
|
-
});
|
|
42
|
-
return { status: "ok", path: resolved, output };
|
|
41
|
+
const targetPath = path.resolve(args.path);
|
|
42
|
+
const raw = await fs.promises.readFile(targetPath, 'utf8');
|
|
43
|
+
const lines = raw.split('\\n');
|
|
44
|
+
const offset = args.offset ? args.offset - 1 : 0;
|
|
45
|
+
const slice = args.limit ? lines.slice(offset, offset + args.limit) : lines.slice(offset);
|
|
46
|
+
const totalLines = lines.length;
|
|
47
|
+
return { status: 'ok', path: targetPath, content: slice.join('\\n'), totalLines, returnedLines: slice.length, offset: offset + 1 };
|
|
43
48
|
`,
|
|
44
49
|
},
|
|
45
50
|
exec: {
|
|
@@ -384,7 +389,7 @@ const SEED_TOOLS = {
|
|
|
384
389
|
properties: {
|
|
385
390
|
name: { type: 'string', description: 'Short identifier for this cron, e.g. "backup-nightly".' },
|
|
386
391
|
schedule: { type: 'string', description: 'Cron expression, e.g. "0 3 * * *" for 3am daily. For a one-time task, compute the exact time from get_current_time and express it as a cron expression.' },
|
|
387
|
-
prompt: { type: 'string', description: 'The task prompt the agent will receive when this cron fires. Must be self-contained.
|
|
392
|
+
prompt: { type: 'string', description: 'The task prompt the agent will receive when this cron fires. Must be self-contained. If notification is desired, include: "use send_telegram_message to notify the user with the result. Prefix the message with [Cron: \"<name>\" | <timestamp>] where <name> is the cron name and <timestamp> is the current date and time."' },
|
|
388
393
|
once: { type: 'boolean', description: 'If true, the cron deletes itself after firing once. Use for one-time reminders or tasks.' },
|
|
389
394
|
},
|
|
390
395
|
required: ['name', 'schedule', 'prompt'],
|
|
@@ -508,24 +513,40 @@ const SEED_TOOLS = {
|
|
|
508
513
|
type: 'function',
|
|
509
514
|
function: {
|
|
510
515
|
name: 'read_cron_log',
|
|
511
|
-
description: 'Read
|
|
516
|
+
description: 'Read cron execution logs. Without id: returns recent runs across all crons (last 8 most recently active cron files, 5 entries each). With id: returns runs for that specific cron.',
|
|
512
517
|
parameters: {
|
|
513
518
|
type: 'object',
|
|
514
519
|
properties: {
|
|
515
|
-
id: { type: 'string', description: 'The cron id.' },
|
|
516
|
-
limit: { type: 'number', description: 'Max entries to return. Defaults to 20.' },
|
|
520
|
+
id: { type: 'string', description: 'The cron id. Omit to get an overview across all crons.' },
|
|
521
|
+
limit: { type: 'number', description: 'Max entries to return when reading a specific cron. Defaults to 20.' },
|
|
517
522
|
},
|
|
518
|
-
required: [
|
|
523
|
+
required: [],
|
|
519
524
|
},
|
|
520
525
|
},
|
|
521
526
|
},
|
|
522
527
|
code: `
|
|
523
528
|
const logsDir = path.join(process.env.HOME, '.jarvis/logs');
|
|
529
|
+
if (!args.id) {
|
|
530
|
+
const files = await fs.promises.readdir(logsDir).catch(() => []);
|
|
531
|
+
const cronFiles = files.filter(f => f.startsWith('cron-') && f.endsWith('.jsonl'));
|
|
532
|
+
const withMtime = await Promise.all(cronFiles.map(async f => {
|
|
533
|
+
const stat = await fs.promises.stat(path.join(logsDir, f));
|
|
534
|
+
return { file: f, mtime: stat.mtimeMs };
|
|
535
|
+
}));
|
|
536
|
+
withMtime.sort((a, b) => b.mtime - a.mtime);
|
|
537
|
+
const allEntries = [];
|
|
538
|
+
for (const { file } of withMtime.slice(0, 8)) {
|
|
539
|
+
const content = await fs.promises.readFile(path.join(logsDir, file), 'utf8').catch(() => '');
|
|
540
|
+
const lines = content.trim().split('\\n').filter(Boolean);
|
|
541
|
+
allEntries.push(...lines.slice(-5).map(line => JSON.parse(line)));
|
|
542
|
+
}
|
|
543
|
+
allEntries.sort((a, b) => new Date(b.ts) - new Date(a.ts));
|
|
544
|
+
return { status: 'ok', entries: allEntries };
|
|
545
|
+
}
|
|
524
546
|
const logFile = path.join(logsDir, 'cron-' + args.id + '.jsonl');
|
|
525
547
|
const content = await fs.promises.readFile(logFile, 'utf8').catch(() => '');
|
|
526
548
|
const lines = content.trim().split('\\n').filter(Boolean);
|
|
527
|
-
const
|
|
528
|
-
const entries = lines.slice(-limit).map(line => JSON.parse(line));
|
|
549
|
+
const entries = lines.slice(-(args.limit || 20)).map(line => JSON.parse(line));
|
|
529
550
|
return { status: 'ok', entries };
|
|
530
551
|
`,
|
|
531
552
|
},
|
|
@@ -557,50 +578,6 @@ const SEED_TOOLS = {
|
|
|
557
578
|
return { status: 'ok', name: args.name, content };
|
|
558
579
|
`,
|
|
559
580
|
},
|
|
560
|
-
get_recent_sessions: {
|
|
561
|
-
definition: {
|
|
562
|
-
type: 'function',
|
|
563
|
-
function: {
|
|
564
|
-
name: 'get_recent_sessions',
|
|
565
|
-
description: 'Returns the most recent sessions with their titles and timestamps. Use this to find previous conversations.',
|
|
566
|
-
parameters: {
|
|
567
|
-
type: 'object',
|
|
568
|
-
properties: {
|
|
569
|
-
limit: {
|
|
570
|
-
type: 'number',
|
|
571
|
-
description: 'Number of recent sessions to return. Defaults to 2.',
|
|
572
|
-
},
|
|
573
|
-
},
|
|
574
|
-
required: [],
|
|
575
|
-
},
|
|
576
|
-
},
|
|
577
|
-
},
|
|
578
|
-
code: `const logsDir = path.join(process.env.HOME, '.jarvis/logs'); const limit = args.limit || 2; const files = await fs.promises.readdir(logsDir).catch(() => []); const sessionFiles = files.filter(f => f.startsWith('session-') && f.endsWith('.jsonl')); const sessions = []; for (const file of sessionFiles) { const sessionId = file.replace('session-', '').replace('.jsonl', ''); const content = await fs.promises.readFile(path.join(logsDir, file), 'utf8'); const lines = content.trim().split('\\n').filter(Boolean); if (lines.length === 0) continue; const firstEntry = JSON.parse(lines[0]); const lastEntry = JSON.parse(lines[lines.length - 1]); sessions.push({ sessionId, title: (firstEntry.logSummary || '').substring(0, 80), lastTs: lastEntry.ts }); } sessions.sort((a, b) => new Date(b.lastTs) - new Date(a.lastTs)); return { status: 'ok', sessions: sessions.slice(0, limit) };`,
|
|
579
|
-
},
|
|
580
|
-
read_session_log: {
|
|
581
|
-
definition: {
|
|
582
|
-
type: 'function',
|
|
583
|
-
function: {
|
|
584
|
-
name: 'read_session_log',
|
|
585
|
-
description: 'Read JSONL log entries for a given session. Use this to inspect what happened in a previous run, including tool calls, errors, and summaries.',
|
|
586
|
-
parameters: {
|
|
587
|
-
type: 'object',
|
|
588
|
-
properties: {
|
|
589
|
-
sessionId: {
|
|
590
|
-
type: 'string',
|
|
591
|
-
description: 'The session ID to read logs for.',
|
|
592
|
-
},
|
|
593
|
-
limit: {
|
|
594
|
-
type: 'number',
|
|
595
|
-
description: 'Maximum number of entries to return (from the end). Defaults to 20.',
|
|
596
|
-
},
|
|
597
|
-
},
|
|
598
|
-
required: ['sessionId'],
|
|
599
|
-
},
|
|
600
|
-
},
|
|
601
|
-
},
|
|
602
|
-
code: `const logsDir = path.join(process.env.HOME, '.jarvis/logs'); const logFile = path.join(logsDir, 'session-' + args.sessionId + '.jsonl'); const content = await fs.promises.readFile(logFile, 'utf8').catch(() => ''); const lines = content.trim().split('\\n').filter(Boolean); const limit = args.limit || 20; const entries = lines.slice(-limit).map(line => JSON.parse(line)); return { status: 'ok', entries };`,
|
|
603
|
-
},
|
|
604
581
|
};
|
|
605
582
|
|
|
606
583
|
export function seedTools() {
|