naisys 1.0.3 → 1.2.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 +20 -4
- package/bin/comment +4 -0
- package/bin/endsession +3 -0
- package/bin/llmail +3 -0
- package/bin/llmynx +3 -0
- package/{naisys.sh → bin/naisys} +1 -1
- package/bin/pause +3 -0
- package/dist/apps/llmail.js +13 -7
- package/dist/apps/llmynx.js +29 -29
- package/dist/command/commandHandler.js +10 -1
- package/dist/command/commandLoop.js +14 -13
- package/dist/command/commandProtection.js +49 -0
- package/dist/command/promptBuilder.js +7 -0
- package/dist/command/shellCommand.js +18 -1
- package/dist/command/shellWrapper.js +26 -21
- package/dist/config.js +59 -12
- package/dist/llm/contextManager.js +4 -17
- package/dist/llm/llmService.js +22 -9
- package/dist/utils/enums.js +9 -0
- package/package.json +16 -14
package/README.md
CHANGED
|
@@ -11,6 +11,10 @@ vim or nano so point the LLM to use cat to read/write files in a single operatio
|
|
|
11
11
|
|
|
12
12
|
[NPM](https://www.npmjs.com/package/naisys) | [Website](https://naisys.org) | [Discord](https://discord.gg/JBUPWSbaEt) | [Demo Video](https://www.youtube.com/watch?v=Ttya3ixjumo)
|
|
13
13
|
|
|
14
|
+
```bash
|
|
15
|
+
npm install -g naisys
|
|
16
|
+
```
|
|
17
|
+
|
|
14
18
|
#### Node.js is used to create a simple proxy shell environment for the LLM that
|
|
15
19
|
|
|
16
20
|
- Helps the LLM keep track of its current context size
|
|
@@ -61,7 +65,7 @@ title: Software Engineer
|
|
|
61
65
|
|
|
62
66
|
# The model to use for console interactions
|
|
63
67
|
# (gpt4turbo, gpt4turbo, gemini-pro, claude3sonnet, claude3opus, local)
|
|
64
|
-
|
|
68
|
+
shellModel: claude3sonnet
|
|
65
69
|
|
|
66
70
|
# The model to use for llmynx, pre-processing websites to fit into a smaller context
|
|
67
71
|
webModel: gpt3turbo
|
|
@@ -85,14 +89,26 @@ tokenMax: 5000
|
|
|
85
89
|
# No value or zero means wait indefinitely (debug driven)
|
|
86
90
|
debugPauseSeconds: 5
|
|
87
91
|
|
|
88
|
-
# If true, regardless of the debugPauseSeconds, the agent will
|
|
89
|
-
#
|
|
92
|
+
# If true, regardless of the debugPauseSeconds, the agent will wake up on messages
|
|
93
|
+
# Useful for agents with long debugPauseSeconds, so that they can wake up and reply quickly
|
|
90
94
|
wakeOnMessage: false
|
|
91
95
|
|
|
92
96
|
# The maximum amount to spend on LLM interactions
|
|
93
97
|
# Once reached the agent will stop and this value will need to be increased to continue
|
|
94
98
|
spendLimitDollars: 2.00
|
|
95
|
-
|
|
99
|
+
|
|
100
|
+
# Command Protection: Useful for agents you want to restrict from modifying the system
|
|
101
|
+
# None: Commands from the LLM run automatically, this is the default setting as well if the value is not set
|
|
102
|
+
# Manual: Every command the LLM wants to run has to be approved [y/n]. Not very autonomous.
|
|
103
|
+
# Auto: All commands are run through the separate LLM instace that will check to see if the command is safe
|
|
104
|
+
commandProtection: "none"
|
|
105
|
+
|
|
106
|
+
# Run these commands on session start, in the example below the agent will see how to use mail and a list of other agents
|
|
107
|
+
initialCommands:
|
|
108
|
+
- llmail users
|
|
109
|
+
- llmail help
|
|
110
|
+
- cat ${env.NAISYS_FOLDER}/home/${agent.username}/PLAN.md
|
|
111
|
+
# Additional custom variables can be defined here and/or in the agent config to be loaded into the agent prompt
|
|
96
112
|
```
|
|
97
113
|
|
|
98
114
|
- Run `naisys <path to yaml or directory>`
|
package/bin/comment
ADDED
package/bin/endsession
ADDED
package/bin/llmail
ADDED
package/bin/llmynx
ADDED
package/{naisys.sh → bin/naisys}
RENAMED
|
@@ -12,7 +12,7 @@ fi
|
|
|
12
12
|
|
|
13
13
|
# Resolves the location of naisys from the bin directory
|
|
14
14
|
SCRIPT=$(readlink -f "$0" || echo "$0")
|
|
15
|
-
SCRIPT_DIR=$(dirname "$SCRIPT")
|
|
15
|
+
SCRIPT_DIR=$(dirname "$SCRIPT")/..
|
|
16
16
|
|
|
17
17
|
# if path is a yaml file then start a single agent
|
|
18
18
|
if [ -f "$1" ]; then
|
package/bin/pause
ADDED
package/dist/apps/llmail.js
CHANGED
|
@@ -6,9 +6,8 @@ import * as utilities from "../utils/utilities.js";
|
|
|
6
6
|
import { naisysToHostPath } from "../utils/utilities.js";
|
|
7
7
|
const _dbFilePath = naisysToHostPath(`${config.naisysFolder}/lib/llmail.db`);
|
|
8
8
|
let _myUserId = -1;
|
|
9
|
-
|
|
10
|
-
const _threadTokenMax = config.
|
|
11
|
-
const _messageTokenMax = _threadTokenMax / 5; // Given the above a 400 token max, and 5 big messages per thread
|
|
9
|
+
/** Threading is not currently used so this doesn't matter */
|
|
10
|
+
const _threadTokenMax = config.mailMessageTokenMax * 5;
|
|
12
11
|
/** The 'non-simple' version of this is a thread first mail system. Where agents can create threads, add users, and reply to threads, etc..
|
|
13
12
|
* The problem with this was the agents were too chatty with so many mail commands, wasting context replying, reading threads, etc..
|
|
14
13
|
* Simple mode only has two commands. It still requires db persistance to support offline agents. */
|
|
@@ -85,7 +84,7 @@ export async function handleCommand(args) {
|
|
|
85
84
|
if (simpleMode) {
|
|
86
85
|
return `llmail <command>
|
|
87
86
|
users: Get list of users on the system
|
|
88
|
-
send "<users>" "subject" "message": Send a message. ${
|
|
87
|
+
send "<users>" "subject" "message": Send a message. ${config.mailMessageTokenMax} token max.`;
|
|
89
88
|
}
|
|
90
89
|
else {
|
|
91
90
|
return `llmail <command>
|
|
@@ -138,7 +137,8 @@ export async function handleCommand(args) {
|
|
|
138
137
|
await init();
|
|
139
138
|
return "llmail database reset";
|
|
140
139
|
default:
|
|
141
|
-
return "
|
|
140
|
+
return ("Error, unknown command. See valid commands below:\n" +
|
|
141
|
+
(await handleCommand("help")));
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
export async function getUnreadThreads() {
|
|
@@ -339,12 +339,18 @@ async function getUser(db, username) {
|
|
|
339
339
|
}
|
|
340
340
|
function validateMsgTokenCount(message) {
|
|
341
341
|
const msgTokenCount = utilities.getTokenCount(message);
|
|
342
|
-
if (msgTokenCount >
|
|
343
|
-
throw `Error: Message is ${msgTokenCount} tokens, exceeding the limit of ${
|
|
342
|
+
if (msgTokenCount > config.mailMessageTokenMax) {
|
|
343
|
+
throw `Error: Message is ${msgTokenCount} tokens, exceeding the limit of ${config.mailMessageTokenMax} tokens`;
|
|
344
344
|
}
|
|
345
345
|
return msgTokenCount;
|
|
346
346
|
}
|
|
347
347
|
async function usingDatabase(run) {
|
|
348
348
|
return dbUtils.usingDatabase(_dbFilePath, run);
|
|
349
349
|
}
|
|
350
|
+
export async function hasMultipleUsers() {
|
|
351
|
+
return await usingDatabase(async (db) => {
|
|
352
|
+
const users = await db.all("SELECT * FROM Users");
|
|
353
|
+
return users.length > 1;
|
|
354
|
+
});
|
|
355
|
+
}
|
|
350
356
|
//# sourceMappingURL=llmail.js.map
|
package/dist/apps/llmynx.js
CHANGED
|
@@ -15,53 +15,50 @@ let _nextGlobalLinkNum = 1;
|
|
|
15
15
|
export async function handleCommand(cmdArgs) {
|
|
16
16
|
outputInDebugMode("LLMYNX DEBUG MODE IS ON");
|
|
17
17
|
const argParams = cmdArgs.split(" ");
|
|
18
|
-
const defualtTokenMax = config.agent.tokenMax / 8;
|
|
19
18
|
if (!argParams[0]) {
|
|
20
19
|
argParams[0] = "help";
|
|
21
20
|
}
|
|
22
21
|
switch (argParams[0]) {
|
|
23
22
|
case "help":
|
|
24
|
-
return `llmynx <command> (results will be reduced to around ${
|
|
23
|
+
return `llmynx <command> (results will be reduced to around ${config.webTokenMax})
|
|
25
24
|
search <query>: Search google for the given query
|
|
26
25
|
open <url>: Opens the given url. Links are represented as numbers in brackets which prefix the word they are linking like [123]
|
|
27
26
|
follow <link number>: Opens the given link number. Link numbers work across all previous outputs
|
|
28
|
-
links <url> <page>: Lists only the links for the given url. Use the page number to get more links
|
|
27
|
+
links <url> <page>: Lists only the links for the given url. Use the page number to get more links
|
|
28
|
+
|
|
29
|
+
*llmynx does not support input. Use llmynx or curl to call APIs directly*`;
|
|
29
30
|
case "search": {
|
|
30
31
|
const query = argParams.slice(1).join(" ");
|
|
31
|
-
return await loadUrl("https://www.google.com/search?q=" + encodeURIComponent(query),
|
|
32
|
-
true, true);
|
|
32
|
+
return await loadUrl("https://www.google.com/search?q=" + encodeURIComponent(query), true, true);
|
|
33
33
|
}
|
|
34
34
|
case "open": {
|
|
35
35
|
const url = argParams[1];
|
|
36
|
-
|
|
37
|
-
const tokenMax = isNumber ? parseInt(argParams[2]) : defualtTokenMax;
|
|
38
|
-
return await loadUrl(url, tokenMax, false, true);
|
|
36
|
+
return await loadUrl(url, false, true);
|
|
39
37
|
}
|
|
40
38
|
case "follow": {
|
|
41
39
|
const linkNum = parseInt(argParams[1]);
|
|
42
|
-
const isNumber = !isNaN(parseInt(argParams[2]));
|
|
43
|
-
const tokenMax = isNumber ? parseInt(argParams[2]) : defualtTokenMax;
|
|
44
40
|
const linkUrl = _globalLinkMap.get(linkNum);
|
|
45
41
|
if (!linkUrl) {
|
|
46
42
|
return "Link number not found";
|
|
47
43
|
}
|
|
48
|
-
return await loadUrl(linkUrl,
|
|
44
|
+
return await loadUrl(linkUrl, true, false);
|
|
49
45
|
}
|
|
50
46
|
case "links": {
|
|
51
47
|
const url = argParams[1];
|
|
52
48
|
const isNumber = !isNaN(parseInt(argParams[2]));
|
|
53
49
|
const pageNumber = isNumber ? parseInt(argParams[2]) : 1;
|
|
54
|
-
return await loadUrl(url,
|
|
50
|
+
return await loadUrl(url, false, false, pageNumber);
|
|
55
51
|
}
|
|
56
52
|
// Secret command to toggle debug mode
|
|
57
53
|
case "debug":
|
|
58
54
|
debugMode = !debugMode;
|
|
59
55
|
return "Debug mode toggled " + (debugMode ? "on" : "off");
|
|
60
56
|
default:
|
|
61
|
-
return "
|
|
57
|
+
return ("Error, unknown command. See valid commands below:\n" +
|
|
58
|
+
(await handleCommand("help")));
|
|
62
59
|
}
|
|
63
60
|
}
|
|
64
|
-
async function loadUrl(url,
|
|
61
|
+
async function loadUrl(url, showUrl, showFollowHint, linkPageAsContent) {
|
|
65
62
|
let content = await runLynx(url);
|
|
66
63
|
let links = "";
|
|
67
64
|
// Reverse find 'References: ' and cut everything after it from the content
|
|
@@ -79,13 +76,13 @@ async function loadUrl(url, tokenMax, showUrl, showFollowHint, linkPageAsContent
|
|
|
79
76
|
outputInDebugMode(`Content Token size: ${contentTokenSize}\n` +
|
|
80
77
|
`Links Token size: ${linksTokenSize}`);
|
|
81
78
|
// Reduce content using LLM if it's over the token max
|
|
82
|
-
if (contentTokenSize >
|
|
79
|
+
if (contentTokenSize > config.webTokenMax) {
|
|
83
80
|
const model = getLLModel(config.agent.webModel);
|
|
84
81
|
// For example if context is 16k, and max tokens is 2k, 3k with 1.5x overrun
|
|
85
82
|
// That would be 3k for the current compressed content, 10k for the chunk, and 3k for the output
|
|
86
|
-
let tokenChunkSize = model.maxTokens -
|
|
83
|
+
let tokenChunkSize = model.maxTokens - config.webTokenMax * 2 * 1.5;
|
|
87
84
|
if (linkPageAsContent) {
|
|
88
|
-
tokenChunkSize =
|
|
85
|
+
tokenChunkSize = config.webTokenMax;
|
|
89
86
|
}
|
|
90
87
|
outputInDebugMode(`Token max chunk size: ${tokenChunkSize}`);
|
|
91
88
|
const pieceCount = Math.ceil(contentTokenSize / tokenChunkSize);
|
|
@@ -100,10 +97,10 @@ async function loadUrl(url, tokenMax, showUrl, showFollowHint, linkPageAsContent
|
|
|
100
97
|
}
|
|
101
98
|
continue;
|
|
102
99
|
}
|
|
103
|
-
output.comment(`Processing Piece ${i + 1} of ${pieceCount}...`);
|
|
100
|
+
output.comment(`Processing Piece ${i + 1} of ${pieceCount} with ${model.key}...`);
|
|
104
101
|
outputInDebugMode(` Reduced output tokens: ${utilities.getTokenCount(reducedOutput)}\n` +
|
|
105
102
|
` Current Piece tokens: ${utilities.getTokenCount(pieceStr)}`);
|
|
106
|
-
reducedOutput = await llmReduce(url, reducedOutput, i + 1, pieceCount, pieceStr
|
|
103
|
+
reducedOutput = await llmReduce(url, reducedOutput, i + 1, pieceCount, pieceStr);
|
|
107
104
|
}
|
|
108
105
|
if (linkPageAsContent) {
|
|
109
106
|
return "";
|
|
@@ -113,7 +110,7 @@ async function loadUrl(url, tokenMax, showUrl, showFollowHint, linkPageAsContent
|
|
|
113
110
|
output.comment(`Content reduced from ${contentTokenSize} to ${finalTokenSize} tokens`);
|
|
114
111
|
}
|
|
115
112
|
else {
|
|
116
|
-
output.comment(`Content is already under ${
|
|
113
|
+
output.comment(`Content is already under ${config.webTokenMax} tokens.`);
|
|
117
114
|
}
|
|
118
115
|
// Prefix content with url if following as otherwise the url is never shown
|
|
119
116
|
if (showUrl) {
|
|
@@ -132,22 +129,25 @@ async function runLynx(url) {
|
|
|
132
129
|
const modeParams = "";
|
|
133
130
|
const ifWindows = os.platform() === "win32" ? "wsl " : "";
|
|
134
131
|
exec(`${ifWindows}lynx -dump ${modeParams} "${url}"`, (error, stdout, stderr) => {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
let output = "";
|
|
133
|
+
if (stdout) {
|
|
134
|
+
output += stdout;
|
|
135
|
+
}
|
|
136
|
+
// I've only seen either/or, but just in case
|
|
137
|
+
if (stdout && stderr) {
|
|
138
|
+
output += "\nError:\n";
|
|
138
139
|
}
|
|
139
140
|
if (stderr) {
|
|
140
|
-
|
|
141
|
-
return;
|
|
141
|
+
output += stderr;
|
|
142
142
|
}
|
|
143
|
-
resolve(
|
|
143
|
+
resolve(output);
|
|
144
144
|
});
|
|
145
145
|
});
|
|
146
146
|
}
|
|
147
|
-
async function llmReduce(url, reducedOutput, pieceNumber, pieceTotal, pieceStr
|
|
147
|
+
async function llmReduce(url, reducedOutput, pieceNumber, pieceTotal, pieceStr) {
|
|
148
148
|
const systemMessage = `You will be iteratively fed the web page ${url} broken into ${pieceTotal} sequential equally sized pieces.
|
|
149
149
|
Each piece should be reduced into the final content in order to maintain the meaning of the page while reducing verbosity and duplication.
|
|
150
|
-
The final output should be around ${
|
|
150
|
+
The final output should be around ${config.webTokenMax} tokens.
|
|
151
151
|
Don't remove links which are represented as numbers in brackets which prefix the word they are linking like [123].
|
|
152
152
|
Try to prioritize content of substance over advertising content.`;
|
|
153
153
|
const content = `Web page piece ${pieceNumber} of ${pieceTotal}:
|
|
@@ -156,7 +156,7 @@ ${pieceStr}
|
|
|
156
156
|
Current reduced content:
|
|
157
157
|
${reducedOutput}
|
|
158
158
|
|
|
159
|
-
Please merge the new piece into the existing reduced content above while keeping the result to around ${
|
|
159
|
+
Please merge the new piece into the existing reduced content above while keeping the result to around ${config.webTokenMax} tokens.
|
|
160
160
|
|
|
161
161
|
Merged reduced content:
|
|
162
162
|
`;
|
|
@@ -11,6 +11,7 @@ import * as logService from "../utils/logService.js";
|
|
|
11
11
|
import * as output from "../utils/output.js";
|
|
12
12
|
import { OutputColor } from "../utils/output.js";
|
|
13
13
|
import * as utilities from "../utils/utilities.js";
|
|
14
|
+
import * as commandProtection from "./commandProtection.js";
|
|
14
15
|
import * as promptBuilder from "./promptBuilder.js";
|
|
15
16
|
import * as shellCommand from "./shellCommand.js";
|
|
16
17
|
export var NextCommandAction;
|
|
@@ -20,7 +21,7 @@ export var NextCommandAction;
|
|
|
20
21
|
NextCommandAction[NextCommandAction["ExitApplication"] = 2] = "ExitApplication";
|
|
21
22
|
})(NextCommandAction || (NextCommandAction = {}));
|
|
22
23
|
export let previousSessionNotes = await logService.getPreviousEndSessionNote();
|
|
23
|
-
export async function
|
|
24
|
+
export async function processCommand(prompt, consoleInput) {
|
|
24
25
|
// We process the lines one at a time so we can support multiple commands with line breaks
|
|
25
26
|
let firstLine = true;
|
|
26
27
|
let processNextLLMpromptBlock = true;
|
|
@@ -47,12 +48,20 @@ export async function consoleInput(prompt, consoleInput) {
|
|
|
47
48
|
await output.commentAndLog("Continuing with next command from same LLM response...");
|
|
48
49
|
await contextManager.append(input, ContentSource.LLM);
|
|
49
50
|
}
|
|
51
|
+
// Run write protection checks if enabled
|
|
52
|
+
const { commandAllowed, rejectReason } = await commandProtection.validateCommand(input);
|
|
53
|
+
if (!commandAllowed) {
|
|
54
|
+
await output.errorAndLog(`Write Protection Triggered`);
|
|
55
|
+
await contextManager.append(rejectReason || "Unknown");
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
50
58
|
}
|
|
51
59
|
const cmdParams = input.split(" ");
|
|
52
60
|
const cmdArgs = input.slice(cmdParams[0].length).trim();
|
|
53
61
|
switch (cmdParams[0]) {
|
|
54
62
|
case "comment": {
|
|
55
63
|
// Important - Hint the LLM to turn their thoughts into accounts
|
|
64
|
+
// ./bin/comment shell script has the same message
|
|
56
65
|
await contextManager.append("Comment noted. Try running commands now to achieve your goal.");
|
|
57
66
|
break;
|
|
58
67
|
}
|
|
@@ -18,7 +18,7 @@ import * as promptBuilder from "./promptBuilder.js";
|
|
|
18
18
|
const maxErrorCount = 5;
|
|
19
19
|
export async function run() {
|
|
20
20
|
// Show Agent Config exept the agent prompt
|
|
21
|
-
await output.commentAndLog(`Agent configured to use ${config.agent.
|
|
21
|
+
await output.commentAndLog(`Agent configured to use ${config.agent.shellModel} model`);
|
|
22
22
|
// Show System Message
|
|
23
23
|
await output.commentAndLog("System Message:");
|
|
24
24
|
const systemMessage = contextManager.getSystemMessage();
|
|
@@ -35,28 +35,29 @@ export async function run() {
|
|
|
35
35
|
await output.commentAndLog("Starting Context:");
|
|
36
36
|
await contextManager.append("Previous Session Note:");
|
|
37
37
|
await contextManager.append(commandHandler.previousSessionNotes || "None");
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
for (const initialCommand of config.agent.initialCommands) {
|
|
39
|
+
await commandHandler.processCommand(await promptBuilder.getPrompt(0, false), config.resolveConfigVars(initialCommand));
|
|
40
|
+
}
|
|
40
41
|
inputMode.toggle(InputMode.Debug);
|
|
41
42
|
let pauseSeconds = config.agent.debugPauseSeconds;
|
|
42
43
|
let wakeOnMessage = config.agent.wakeOnMessage;
|
|
43
44
|
while (nextCommandAction == NextCommandAction.Continue) {
|
|
44
45
|
const prompt = await promptBuilder.getPrompt(pauseSeconds, wakeOnMessage);
|
|
45
|
-
let
|
|
46
|
+
let consoleInput = "";
|
|
46
47
|
// Debug command prompt
|
|
47
48
|
if (inputMode.current === InputMode.Debug) {
|
|
48
|
-
|
|
49
|
+
consoleInput = await promptBuilder.getInput(`${prompt}`, pauseSeconds, wakeOnMessage);
|
|
49
50
|
}
|
|
50
51
|
// LLM command prompt
|
|
51
52
|
else if (inputMode.current === InputMode.LLM) {
|
|
52
53
|
const workingMsg = prompt +
|
|
53
|
-
chalk[output.OutputColor.loading](`LLM (${config.agent.
|
|
54
|
+
chalk[output.OutputColor.loading](`LLM (${config.agent.shellModel}) Working...`);
|
|
54
55
|
try {
|
|
55
|
-
await
|
|
56
|
-
await
|
|
56
|
+
await checkNewMailNotification();
|
|
57
|
+
await checkContextLimitWarning();
|
|
57
58
|
await contextManager.append(prompt, ContentSource.ConsolePrompt);
|
|
58
59
|
process.stdout.write(workingMsg);
|
|
59
|
-
|
|
60
|
+
consoleInput = await llmService.query(config.agent.shellModel, contextManager.getSystemMessage(), contextManager.messages, "console");
|
|
60
61
|
clearPromptMessage(workingMsg);
|
|
61
62
|
}
|
|
62
63
|
catch (e) {
|
|
@@ -73,7 +74,7 @@ export async function run() {
|
|
|
73
74
|
// Run the command
|
|
74
75
|
try {
|
|
75
76
|
({ nextCommandAction, pauseSeconds, wakeOnMessage } =
|
|
76
|
-
await commandHandler.
|
|
77
|
+
await commandHandler.processCommand(prompt, consoleInput));
|
|
77
78
|
if (inputMode.current == InputMode.LLM) {
|
|
78
79
|
llmErrorCount = 0;
|
|
79
80
|
}
|
|
@@ -85,7 +86,7 @@ export async function run() {
|
|
|
85
86
|
}
|
|
86
87
|
// If the user is in debug mode and they didn't enter anything, switch to LLM
|
|
87
88
|
// If in LLM mode, auto switch back to debug
|
|
88
|
-
if ((inputMode.current == InputMode.Debug && !
|
|
89
|
+
if ((inputMode.current == InputMode.Debug && !consoleInput) ||
|
|
89
90
|
inputMode.current == InputMode.LLM) {
|
|
90
91
|
inputMode.toggle();
|
|
91
92
|
}
|
|
@@ -136,7 +137,7 @@ async function handleErrorAndSwitchToDebugMode(e, llmErrorCount, addToContext) {
|
|
|
136
137
|
wakeOnMessage,
|
|
137
138
|
};
|
|
138
139
|
}
|
|
139
|
-
async function
|
|
140
|
+
async function checkNewMailNotification() {
|
|
140
141
|
// Check for unread threads
|
|
141
142
|
const unreadThreads = await llmail.getUnreadThreads();
|
|
142
143
|
if (!unreadThreads.length) {
|
|
@@ -174,7 +175,7 @@ async function displayNewMail() {
|
|
|
174
175
|
`Use llmail read <id>' to read the thread, but be mindful you are close to the token limit for the session.`, ContentSource.Console);
|
|
175
176
|
}
|
|
176
177
|
}
|
|
177
|
-
async function
|
|
178
|
+
async function checkContextLimitWarning() {
|
|
178
179
|
const tokenCount = contextManager.getTokenCount();
|
|
179
180
|
const tokenMax = config.agent.tokenMax;
|
|
180
181
|
if (tokenCount > tokenMax) {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as config from "../config.js";
|
|
2
|
+
import { LlmRole } from "../llm/llmDtos.js";
|
|
3
|
+
import * as llmService from "../llm/llmService.js";
|
|
4
|
+
import { CommandProtection } from "../utils/enums.js";
|
|
5
|
+
import * as output from "../utils/output.js";
|
|
6
|
+
import * as promptBuilder from "./promptBuilder.js";
|
|
7
|
+
export async function validateCommand(command) {
|
|
8
|
+
switch (config.agent.commandProtection) {
|
|
9
|
+
case CommandProtection.None:
|
|
10
|
+
return {
|
|
11
|
+
commandAllowed: true,
|
|
12
|
+
};
|
|
13
|
+
case CommandProtection.Manual: {
|
|
14
|
+
const confirmation = await promptBuilder.getCommandConfirmation();
|
|
15
|
+
const commandAllowed = confirmation.toLowerCase() === "y";
|
|
16
|
+
return {
|
|
17
|
+
commandAllowed,
|
|
18
|
+
rejectReason: commandAllowed ? undefined : "Command denied by admin",
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
case CommandProtection.Auto:
|
|
22
|
+
return await autoValidateCommand(command);
|
|
23
|
+
default:
|
|
24
|
+
throw "Write protection not configured correctly";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function autoValidateCommand(command) {
|
|
28
|
+
output.comment("Checking if command is allowed...");
|
|
29
|
+
const systemMessage = `You are a command validator that checks if shell commands are ok to run.
|
|
30
|
+
The user is 'junior admin' allowed to move around the system, anywhere, and read anything, list anything.
|
|
31
|
+
They are not allowed to execute programs that could modify the system.
|
|
32
|
+
Programs that just give information responses are ok.
|
|
33
|
+
The user is allowed to write to their home directory in ${config.naisysFolder}/home/${config.agent.username}
|
|
34
|
+
In addition to the commands you know are ok, these additional commands are whitelisted:
|
|
35
|
+
llmail, llmynx, comment, endsession, and pause
|
|
36
|
+
Reply with 'allow' to allow the command, otherwise you can give a reason for your rejection.`;
|
|
37
|
+
const response = await llmService.query(config.agent.shellModel, systemMessage, [
|
|
38
|
+
{
|
|
39
|
+
role: LlmRole.User,
|
|
40
|
+
content: command,
|
|
41
|
+
},
|
|
42
|
+
], "write-protection");
|
|
43
|
+
const commandAllowed = response.toLocaleLowerCase().startsWith("allow");
|
|
44
|
+
return {
|
|
45
|
+
commandAllowed,
|
|
46
|
+
rejectReason: commandAllowed ? undefined : "Command Rejected: " + response,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=commandProtection.js.map
|
|
@@ -130,4 +130,11 @@ export function getInput(commandPrompt, pauseSeconds, wakeOnMessage) {
|
|
|
130
130
|
}
|
|
131
131
|
});
|
|
132
132
|
}
|
|
133
|
+
export function getCommandConfirmation() {
|
|
134
|
+
return new Promise((resolve) => {
|
|
135
|
+
_readlineInterface.question(chalk.greenBright("Allow command to run? [y/n] "), (answer) => {
|
|
136
|
+
resolve(answer);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
}
|
|
133
140
|
//# sourceMappingURL=promptBuilder.js.map
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import * as config from "../config.js";
|
|
1
2
|
import * as contextManager from "../llm/contextManager.js";
|
|
2
3
|
import * as inputMode from "../utils/inputMode.js";
|
|
3
4
|
import { InputMode } from "../utils/inputMode.js";
|
|
5
|
+
import * as utilities from "../utils/utilities.js";
|
|
4
6
|
import * as shellWrapper from "./shellWrapper.js";
|
|
5
7
|
export async function handleCommand(input) {
|
|
6
8
|
const cmdParams = input.split(" ");
|
|
@@ -29,7 +31,22 @@ export async function handleCommand(input) {
|
|
|
29
31
|
}
|
|
30
32
|
const output = await shellWrapper.executeCommand(input);
|
|
31
33
|
if (output.value) {
|
|
32
|
-
|
|
34
|
+
let text = output.value;
|
|
35
|
+
let outputLimitExceeded = false;
|
|
36
|
+
const tokenCount = utilities.getTokenCount(text);
|
|
37
|
+
// Prevent too much output from blowing up the context
|
|
38
|
+
if (tokenCount > config.shellOutputTokenMax) {
|
|
39
|
+
outputLimitExceeded = true;
|
|
40
|
+
const trimLength = (text.length * config.shellOutputTokenMax) / tokenCount;
|
|
41
|
+
text =
|
|
42
|
+
text.slice(0, trimLength / 2) +
|
|
43
|
+
"\n\n...\n\n" +
|
|
44
|
+
text.slice(-trimLength / 2);
|
|
45
|
+
}
|
|
46
|
+
await contextManager.append(text);
|
|
47
|
+
if (outputLimitExceeded) {
|
|
48
|
+
await contextManager.append(`\nThe shell command generated too much output (${tokenCount} tokens). Only 2,000 tokens worth are shown above.`);
|
|
49
|
+
}
|
|
33
50
|
}
|
|
34
51
|
response.hasErrors = output.hasErrors;
|
|
35
52
|
return response;
|
|
@@ -39,12 +39,12 @@ async function ensureOpen() {
|
|
|
39
39
|
// Init users home dir on first run, on shell crash/rerun go back to the current path
|
|
40
40
|
if (!_currentPath) {
|
|
41
41
|
output.comment("NEW SHELL OPENED. PID: " + _process.pid);
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
errorIfNotEmpty(await executeCommand(`mkdir -p ${config.naisysFolder}/home/` + config.agent.username));
|
|
43
|
+
errorIfNotEmpty(await executeCommand(`cd ${config.naisysFolder}/home/` + config.agent.username));
|
|
44
44
|
}
|
|
45
45
|
else {
|
|
46
46
|
output.comment("SHELL RESTORED. PID: " + _process.pid);
|
|
47
|
-
|
|
47
|
+
errorIfNotEmpty(await executeCommand("cd " + _currentPath));
|
|
48
48
|
}
|
|
49
49
|
// Stop running commands if one fails
|
|
50
50
|
// Often the LLM will give us back all kinds of invalid commands, we want to break on the first one
|
|
@@ -52,9 +52,9 @@ async function ensureOpen() {
|
|
|
52
52
|
//commentIfNotEmpty(await executeCommand("set -e"));
|
|
53
53
|
}
|
|
54
54
|
/** Basically don't show anything in the console unless there is an error */
|
|
55
|
-
function
|
|
55
|
+
function errorIfNotEmpty(response) {
|
|
56
56
|
if (response.value) {
|
|
57
|
-
output.
|
|
57
|
+
output.error(response.value);
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
export function processOutput(dataStr, eventType) {
|
|
@@ -128,19 +128,22 @@ export async function executeCommand(command) {
|
|
|
128
128
|
const commandWithDelimiter = `${command.trim()}\necho "${_commandDelimiter} LINE:\${LINENO}"\n`;
|
|
129
129
|
//_log += "INPUT: " + commandWithDelimiter;
|
|
130
130
|
_process === null || _process === void 0 ? void 0 : _process.stdin.write(commandWithDelimiter);
|
|
131
|
-
// If no response
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
131
|
+
// If no response, kill and reset the shell, often hanging on some unescaped input
|
|
132
|
+
_currentCommandTimeout = setTimeout(resetShell, config.shellCommmandTimeoutSeconds * 1000);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function resetShell() {
|
|
136
|
+
if (!_resolveCurrentCommand) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
_process === null || _process === void 0 ? void 0 : _process.kill();
|
|
140
|
+
output.error("SHELL TIMEMOUT/KILLED. PID: " + (_process === null || _process === void 0 ? void 0 : _process.pid));
|
|
141
|
+
const outputWithError = _commandOutput.trim() +
|
|
142
|
+
`\nError: Command timed out after ${config.shellCommmandTimeoutSeconds} seconds.`;
|
|
143
|
+
resetProcess();
|
|
144
|
+
_resolveCurrentCommand({
|
|
145
|
+
value: outputWithError,
|
|
146
|
+
hasErrors: true,
|
|
144
147
|
});
|
|
145
148
|
}
|
|
146
149
|
export async function getCurrentPath() {
|
|
@@ -167,14 +170,16 @@ function resetProcess() {
|
|
|
167
170
|
* May also help with common escaping errors */
|
|
168
171
|
function runCommandFromScript(command) {
|
|
169
172
|
const scriptPath = `${config.naisysFolder}/home/${config.agent.username}/.command.tmp.sh`;
|
|
170
|
-
// set -e causes the script to exit on
|
|
173
|
+
// set -e causes the script to exit on the first error
|
|
171
174
|
const scriptContent = `#!/bin/bash
|
|
172
175
|
set -e
|
|
173
176
|
cd ${_currentPath}
|
|
174
177
|
${command.trim()}`;
|
|
175
178
|
// create/writewrite file
|
|
176
179
|
fs.writeFileSync(naisysToHostPath(scriptPath), scriptContent);
|
|
177
|
-
//
|
|
178
|
-
|
|
180
|
+
// `Path` is set to the ./bin folder because custom NAISYS commands that follow shell commands will be handled by the shell, which will fail
|
|
181
|
+
// so we need to remind the LLM that 'naisys commands cannot be used with other commands on the same prompt'
|
|
182
|
+
// `source` will run the script in the current shell, so any change directories in the script will persist in the current shell
|
|
183
|
+
return `PATH=${config.binPath}:$PATH source ${scriptPath}`;
|
|
179
184
|
}
|
|
180
185
|
//# sourceMappingURL=shellWrapper.js.map
|
package/dist/config.js
CHANGED
|
@@ -2,11 +2,16 @@ import { program } from "commander";
|
|
|
2
2
|
import dotenv from "dotenv";
|
|
3
3
|
import * as fs from "fs";
|
|
4
4
|
import yaml from "js-yaml";
|
|
5
|
+
import { CommandProtection } from "./utils/enums.js";
|
|
5
6
|
import { valueFromString } from "./utils/utilities.js";
|
|
6
7
|
program.argument("<agent-path>", "Path to agent configuration file").parse();
|
|
7
8
|
dotenv.config();
|
|
8
9
|
/** The system name that shows after the @ in the command prompt */
|
|
9
10
|
export const hostname = "naisys";
|
|
11
|
+
export const shellOutputTokenMax = 2500; // Limits the size of files that can be read/wrote
|
|
12
|
+
export const shellCommmandTimeoutSeconds = 15; // The number of seconds NAISYS will wait for a shell command to complete
|
|
13
|
+
export const webTokenMax = 2500;
|
|
14
|
+
export const mailMessageTokenMax = 400;
|
|
10
15
|
/* .env is used for global configs across naisys, while agent configs are for the specific agent */
|
|
11
16
|
export const naisysFolder = getEnv("NAISYS_FOLDER", true);
|
|
12
17
|
export const websiteFolder = getEnv("WEBSITE_FOLDER");
|
|
@@ -16,34 +21,45 @@ export const openaiApiKey = getEnv("OPENAI_API_KEY");
|
|
|
16
21
|
export const googleApiKey = getEnv("GOOGLE_API_KEY");
|
|
17
22
|
export const anthropicApiKey = getEnv("ANTHROPIC_API_KEY");
|
|
18
23
|
export const agent = loadAgentConfig();
|
|
19
|
-
function getEnv(key, required) {
|
|
20
|
-
const value = process.env[key];
|
|
21
|
-
if (!value && required) {
|
|
22
|
-
throw `Config: Error, .env ${key} is not defined`;
|
|
23
|
-
}
|
|
24
|
-
return value;
|
|
25
|
-
}
|
|
26
24
|
function loadAgentConfig() {
|
|
27
25
|
const agentPath = program.args[0];
|
|
28
|
-
const
|
|
26
|
+
const config = yaml.load(fs.readFileSync(agentPath, "utf8"));
|
|
29
27
|
// throw if any property is undefined
|
|
30
28
|
for (const key of [
|
|
31
29
|
"username",
|
|
32
30
|
"title",
|
|
33
|
-
"
|
|
31
|
+
"shellModel",
|
|
34
32
|
"webModel",
|
|
35
33
|
"agentPrompt",
|
|
36
34
|
"spendLimitDollars",
|
|
37
35
|
"tokenMax",
|
|
38
|
-
//
|
|
36
|
+
// other properties can be undefined
|
|
39
37
|
]) {
|
|
40
|
-
if (!valueFromString(
|
|
38
|
+
if (!valueFromString(config, key)) {
|
|
41
39
|
throw `Agent config: Error, ${key} is not defined`;
|
|
42
40
|
}
|
|
43
41
|
}
|
|
44
|
-
|
|
42
|
+
// Sanitize input
|
|
43
|
+
if (!config.initialCommands) {
|
|
44
|
+
config.initialCommands = [];
|
|
45
|
+
}
|
|
46
|
+
else if (!Array.isArray(config.initialCommands)) {
|
|
47
|
+
throw `Agent config: Error, 'initialCommands' is not an array`;
|
|
48
|
+
}
|
|
49
|
+
config.debugPauseSeconds = config.debugPauseSeconds
|
|
50
|
+
? Number(config.debugPauseSeconds)
|
|
51
|
+
: 0;
|
|
52
|
+
config.wakeOnMessage = Boolean(config.wakeOnMessage);
|
|
53
|
+
if (!config.commandProtection) {
|
|
54
|
+
config.commandProtection = CommandProtection.None;
|
|
55
|
+
}
|
|
56
|
+
if (!Object.values(CommandProtection).includes(config.commandProtection)) {
|
|
57
|
+
throw `Agent config: Error, 'commandProtection' is not a valid value`;
|
|
58
|
+
}
|
|
59
|
+
return config;
|
|
45
60
|
}
|
|
46
61
|
export const packageVersion = await getVersion();
|
|
62
|
+
export const binPath = getBinPath();
|
|
47
63
|
/** Can only get version from env variable when naisys is started with npm,
|
|
48
64
|
* otherwise need to rip it from the package ourselves relative to where this file is located */
|
|
49
65
|
async function getVersion() {
|
|
@@ -58,4 +74,35 @@ async function getVersion() {
|
|
|
58
74
|
return "0.1";
|
|
59
75
|
}
|
|
60
76
|
}
|
|
77
|
+
function getEnv(key, required) {
|
|
78
|
+
const value = process.env[key];
|
|
79
|
+
if (!value && required) {
|
|
80
|
+
throw `Config: Error, .env ${key} is not defined`;
|
|
81
|
+
}
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
export function resolveConfigVars(templateString) {
|
|
85
|
+
let resolvedString = templateString;
|
|
86
|
+
resolvedString = resolveTemplateVars(resolvedString, "agent", agent);
|
|
87
|
+
resolvedString = resolveTemplateVars(resolvedString, "env", process.env);
|
|
88
|
+
return resolvedString;
|
|
89
|
+
}
|
|
90
|
+
function resolveTemplateVars(templateString, allowedVarString, mappedVar) {
|
|
91
|
+
const pattern = new RegExp(`\\$\\{${allowedVarString}\\.([^}]+)\\}`, "g");
|
|
92
|
+
return templateString.replace(pattern, (match, key) => {
|
|
93
|
+
const value = valueFromString(mappedVar, key);
|
|
94
|
+
if (value === undefined) {
|
|
95
|
+
throw `Agent config: Error, ${key} is not defined`;
|
|
96
|
+
}
|
|
97
|
+
return value;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function getBinPath() {
|
|
101
|
+
// C:/git/naisys/dist/config.js
|
|
102
|
+
let binPath = new URL("../bin", import.meta.url).pathname;
|
|
103
|
+
if (binPath.startsWith("/C:")) {
|
|
104
|
+
binPath = "/mnt/c" + binPath.substring(3);
|
|
105
|
+
}
|
|
106
|
+
return binPath;
|
|
107
|
+
}
|
|
61
108
|
//# sourceMappingURL=config.js.map
|
|
@@ -5,7 +5,6 @@ import * as logService from "../utils/logService.js";
|
|
|
5
5
|
import * as output from "../utils/output.js";
|
|
6
6
|
import { OutputColor } from "../utils/output.js";
|
|
7
7
|
import * as utilities from "../utils/utilities.js";
|
|
8
|
-
import { valueFromString } from "../utils/utilities.js";
|
|
9
8
|
import { LlmRole } from "./llmDtos.js";
|
|
10
9
|
export var ContentSource;
|
|
11
10
|
(function (ContentSource) {
|
|
@@ -23,8 +22,7 @@ export function getSystemMessage() {
|
|
|
23
22
|
// A lot of the stipulations in here are to prevent common LLM mistakes
|
|
24
23
|
// Like we can't jump between standard and special commands in a single prompt, which the LLM will try to do if not warned
|
|
25
24
|
let agentPrompt = config.agent.agentPrompt;
|
|
26
|
-
agentPrompt =
|
|
27
|
-
agentPrompt = resolveTemplateVars(agentPrompt, "env", process.env);
|
|
25
|
+
agentPrompt = config.resolveConfigVars(agentPrompt);
|
|
28
26
|
const systemMessage = `${agentPrompt.trim()}
|
|
29
27
|
|
|
30
28
|
This is a command line interface presenting you with the next command prompt.
|
|
@@ -38,12 +36,12 @@ NAISYS ${config.packageVersion} Shell
|
|
|
38
36
|
Welcome back ${config.agent.username}!
|
|
39
37
|
MOTD:
|
|
40
38
|
Date: ${new Date().toLocaleString()}
|
|
41
|
-
Commands:
|
|
42
|
-
Standard
|
|
39
|
+
LINUX Commands:
|
|
40
|
+
Standard Linux commands are available
|
|
43
41
|
vi and nano are not supported
|
|
44
42
|
Read files with cat. Write files with \`cat > filename << 'EOF'\`
|
|
45
43
|
Do not input notes after the prompt. Only valid commands.
|
|
46
|
-
|
|
44
|
+
NAISYS Commands: (cannot be used with other commands on the same prompt)
|
|
47
45
|
llmail: A local mail system for communicating with your team
|
|
48
46
|
llmynx: A context optimized web browser. Enter 'llmynx help' to learn how to use it
|
|
49
47
|
comment "<thought>": Any non-command output like thinking out loud, prefix with the 'comment' command
|
|
@@ -51,23 +49,12 @@ Special Commands: (Don't mix with standard commands on the same prompt)
|
|
|
51
49
|
endsession "<note>": Ends this session, clears the console log and context.
|
|
52
50
|
The note should help you find your bearings in the next session.
|
|
53
51
|
The note should contain your next goal, and important things should you remember.
|
|
54
|
-
Try to keep the note around 400 tokens.
|
|
55
52
|
Tokens:
|
|
56
53
|
The console log can only hold a certain number of 'tokens' that is specified in the prompt
|
|
57
54
|
Make sure to call endsession before the limit is hit so you can continue your work with a fresh console`;
|
|
58
55
|
_cachedSystemMessage = systemMessage;
|
|
59
56
|
return systemMessage;
|
|
60
57
|
}
|
|
61
|
-
function resolveTemplateVars(templateString, allowedVarString, mappedVar) {
|
|
62
|
-
const pattern = new RegExp(`\\$\\{${allowedVarString}\\.([^}]+)\\}`, "g");
|
|
63
|
-
return templateString.replace(pattern, (match, key) => {
|
|
64
|
-
const value = valueFromString(mappedVar, key);
|
|
65
|
-
if (value === undefined) {
|
|
66
|
-
throw `Agent config: Error, ${key} is not defined`;
|
|
67
|
-
}
|
|
68
|
-
return value;
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
58
|
export let messages = [];
|
|
72
59
|
export async function append(text, source = ContentSource.Console) {
|
|
73
60
|
// Debug runs in a shadow mode where their activity is not recorded in the context
|
package/dist/llm/llmService.js
CHANGED
|
@@ -80,24 +80,37 @@ async function sendWithGoogle(modelKey, systemMessage, context, source) {
|
|
|
80
80
|
if (lastMessage.role !== LlmRole.User) {
|
|
81
81
|
throw "Error, last message on context is not a user message";
|
|
82
82
|
}
|
|
83
|
+
const contextHistory = context
|
|
84
|
+
.filter((m) => m != lastMessage)
|
|
85
|
+
.map((m) => ({
|
|
86
|
+
role: m.role == LlmRole.Assistant ? "model" : "user",
|
|
87
|
+
parts: [
|
|
88
|
+
{
|
|
89
|
+
text: m.content,
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
}));
|
|
83
93
|
const history = [
|
|
84
94
|
{
|
|
85
95
|
role: LlmRole.User, // System role is not supported by Google API
|
|
86
|
-
parts:
|
|
96
|
+
parts: [
|
|
97
|
+
{
|
|
98
|
+
text: systemMessage,
|
|
99
|
+
},
|
|
100
|
+
],
|
|
87
101
|
},
|
|
88
102
|
{
|
|
89
103
|
role: "model",
|
|
90
|
-
parts:
|
|
104
|
+
parts: [
|
|
105
|
+
{
|
|
106
|
+
text: "Understood",
|
|
107
|
+
},
|
|
108
|
+
],
|
|
91
109
|
},
|
|
92
|
-
...
|
|
93
|
-
.filter((m) => m != lastMessage)
|
|
94
|
-
.map((m) => ({
|
|
95
|
-
role: m.role == LlmRole.Assistant ? "model" : LlmRole.User,
|
|
96
|
-
parts: m.content,
|
|
97
|
-
})),
|
|
110
|
+
...contextHistory,
|
|
98
111
|
];
|
|
99
112
|
const chat = googleModel.startChat({
|
|
100
|
-
history
|
|
113
|
+
history,
|
|
101
114
|
generationConfig: {
|
|
102
115
|
maxOutputTokens: 2000,
|
|
103
116
|
},
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/* To separate enums from services which is useful for mocking where the enum
|
|
2
|
+
is used across the code base, but the service it originates from is mocked. */
|
|
3
|
+
export var CommandProtection;
|
|
4
|
+
(function (CommandProtection) {
|
|
5
|
+
CommandProtection["None"] = "none";
|
|
6
|
+
CommandProtection["Manual"] = "manual";
|
|
7
|
+
CommandProtection["Auto"] = "auto";
|
|
8
|
+
})(CommandProtection || (CommandProtection = {}));
|
|
9
|
+
//# sourceMappingURL=enums.js.map
|
package/package.json
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "naisys",
|
|
3
3
|
"description": "Node.js Autonomous Intelligence System",
|
|
4
|
-
"version": "1.0
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/naisys.js",
|
|
7
7
|
"preferGlobal": true,
|
|
8
8
|
"bin": {
|
|
9
|
-
"naisys": "naisys
|
|
9
|
+
"naisys": "./bin/naisys"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
|
-
"compile/run/attachable": "tsc && node --inspect dist/naisys.js ./agents/
|
|
13
|
-
"run agent:
|
|
14
|
-
"run agent:
|
|
12
|
+
"compile/run/attachable": "tsc && node --inspect dist/naisys.js ./agents/webdev-fansite.yaml",
|
|
13
|
+
"run agent:p1": "node dist/naisys.js ./agents/webdev-battle/player1.yaml",
|
|
14
|
+
"run agent:p2": "node dist/naisys.js ./agents/webdev-battle/player2.yaml",
|
|
15
15
|
"clean": "rm -rf dist",
|
|
16
|
-
"
|
|
17
|
-
"compile": "tsc",
|
|
16
|
+
"compile": "tsc --build --verbose",
|
|
18
17
|
"eslint": "npx eslint --rulesdir eslint-rules src",
|
|
19
18
|
"test": "tsc && node --experimental-vm-modules node_modules/jest/bin/jest.js --testPathPattern=dist/__tests__",
|
|
20
19
|
"prettier": "npx prettier --write .",
|
|
21
20
|
"dependency-graph": "madge --image dependency-graph.png dist",
|
|
22
21
|
"detect-cycles": "madge --circular dist",
|
|
23
22
|
"updates:check": "npm-check-updates",
|
|
24
|
-
"updates:apply": "npm-check-updates -u && npm update"
|
|
23
|
+
"updates:apply": "npm-check-updates -u && npm update",
|
|
24
|
+
"npm:publish:dryrun": "npm run clean && npm run compile && npm publish --dry-run",
|
|
25
|
+
"postinstall": "chmod +x ./bin/*"
|
|
25
26
|
},
|
|
26
27
|
"repository": {
|
|
27
28
|
"type": "git",
|
|
@@ -37,22 +38,23 @@
|
|
|
37
38
|
],
|
|
38
39
|
"author": "John Marshall",
|
|
39
40
|
"license": "MIT",
|
|
41
|
+
"homepage": "https://naisys.org",
|
|
40
42
|
"devDependencies": {
|
|
41
43
|
"@types/escape-html": "1.0.4",
|
|
42
44
|
"@types/js-yaml": "4.0.9",
|
|
43
|
-
"@types/node": "20.11.
|
|
45
|
+
"@types/node": "20.11.26",
|
|
44
46
|
"@types/text-table": "0.2.5",
|
|
45
|
-
"@typescript-eslint/eslint-plugin": "7.
|
|
46
|
-
"@typescript-eslint/parser": "7.
|
|
47
|
+
"@typescript-eslint/eslint-plugin": "7.2.0",
|
|
48
|
+
"@typescript-eslint/parser": "7.2.0",
|
|
47
49
|
"eslint": "8.57.0",
|
|
48
50
|
"jest": "29.7.0",
|
|
49
51
|
"prettier": "3.2.5",
|
|
50
52
|
"ts-node": "10.9.2",
|
|
51
|
-
"typescript": "5.
|
|
53
|
+
"typescript": "5.4.2"
|
|
52
54
|
},
|
|
53
55
|
"dependencies": {
|
|
54
|
-
"@anthropic-ai/sdk": "0.
|
|
55
|
-
"@google/generative-ai": "0.
|
|
56
|
+
"@anthropic-ai/sdk": "0.17.2",
|
|
57
|
+
"@google/generative-ai": "0.3.0",
|
|
56
58
|
"chalk": "5.3.0",
|
|
57
59
|
"commander": "12.0.0",
|
|
58
60
|
"dotenv": "16.4.5",
|