naisys 1.2.0 → 1.3.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 +8 -3
- package/bin/comment +0 -0
- package/bin/endsession +0 -0
- package/bin/llmail +0 -0
- package/bin/llmynx +0 -0
- package/bin/naisys +0 -0
- package/bin/pause +0 -0
- package/dist/apps/llmail.js +3 -1
- package/dist/apps/llmynx.js +111 -57
- package/dist/command/commandHandler.js +4 -4
- package/dist/command/commandLoop.js +6 -2
- package/dist/config.js +2 -1
- package/dist/llm/dreamMaker.js +71 -0
- package/dist/utils/logService.js +0 -13
- package/package.json +11 -10
package/README.md
CHANGED
|
@@ -65,10 +65,15 @@ title: Software Engineer
|
|
|
65
65
|
|
|
66
66
|
# The model to use for console interactions
|
|
67
67
|
# (gpt4turbo, gpt4turbo, gemini-pro, claude3sonnet, claude3opus, local)
|
|
68
|
-
shellModel:
|
|
68
|
+
shellModel: gpt4turbo
|
|
69
69
|
|
|
70
|
-
#
|
|
71
|
-
|
|
70
|
+
# Only used between sessions to provide guidance for the next session (use a more powerful model for this)
|
|
71
|
+
# defaults to the shellModel if omitted
|
|
72
|
+
dreamModel: claude3opus
|
|
73
|
+
|
|
74
|
+
# The model to use for llmynx, pre-processing websites to fit into a smaller context (use a cheaper model)
|
|
75
|
+
# defaults to the shellModel if omitted
|
|
76
|
+
webModel: gemini-pro
|
|
72
77
|
|
|
73
78
|
# A system like prompt explaining the agent's role and responsibilities
|
|
74
79
|
# You can use config variables in this string
|
package/bin/comment
CHANGED
|
File without changes
|
package/bin/endsession
CHANGED
|
File without changes
|
package/bin/llmail
CHANGED
|
File without changes
|
package/bin/llmynx
CHANGED
|
File without changes
|
package/bin/naisys
CHANGED
|
File without changes
|
package/bin/pause
CHANGED
|
File without changes
|
package/dist/apps/llmail.js
CHANGED
|
@@ -84,7 +84,9 @@ export async function handleCommand(args) {
|
|
|
84
84
|
if (simpleMode) {
|
|
85
85
|
return `llmail <command>
|
|
86
86
|
users: Get list of users on the system
|
|
87
|
-
send "<users>" "subject" "message": Send a message. ${config.mailMessageTokenMax} token max
|
|
87
|
+
send "<users>" "subject" "message": Send a message. ${config.mailMessageTokenMax} token max.
|
|
88
|
+
|
|
89
|
+
* Attachments are not supported, use file paths to refence files in emails as all users are on the same machine`;
|
|
88
90
|
}
|
|
89
91
|
else {
|
|
90
92
|
return `llmail <command>
|
package/dist/apps/llmynx.js
CHANGED
|
@@ -8,6 +8,7 @@ import * as output from "../utils/output.js";
|
|
|
8
8
|
import * as utilities from "../utils/utilities.js";
|
|
9
9
|
// A bad play on words, but this is like lynx but for LLMs..
|
|
10
10
|
let debugMode = false;
|
|
11
|
+
const _contentCache = new Map();
|
|
11
12
|
/** Links numbers are unique in the context so that `llmynx follow <linknum>` can be called on all previous output */
|
|
12
13
|
const _globalLinkMap = new Map();
|
|
13
14
|
const _globalUrlMap = new Map();
|
|
@@ -20,7 +21,7 @@ export async function handleCommand(cmdArgs) {
|
|
|
20
21
|
}
|
|
21
22
|
switch (argParams[0]) {
|
|
22
23
|
case "help":
|
|
23
|
-
return `llmynx <command> (results will be reduced to around ${config.webTokenMax})
|
|
24
|
+
return `llmynx <command> (results will be reduced to around ${config.webTokenMax} tokens)
|
|
24
25
|
search <query>: Search google for the given query
|
|
25
26
|
open <url>: Opens the given url. Links are represented as numbers in brackets which prefix the word they are linking like [123]
|
|
26
27
|
follow <link number>: Opens the given link number. Link numbers work across all previous outputs
|
|
@@ -29,11 +30,11 @@ export async function handleCommand(cmdArgs) {
|
|
|
29
30
|
*llmynx does not support input. Use llmynx or curl to call APIs directly*`;
|
|
30
31
|
case "search": {
|
|
31
32
|
const query = argParams.slice(1).join(" ");
|
|
32
|
-
return await
|
|
33
|
+
return await loadUrlContent("https://www.google.com/search?q=" + encodeURIComponent(query), true, true);
|
|
33
34
|
}
|
|
34
35
|
case "open": {
|
|
35
36
|
const url = argParams[1];
|
|
36
|
-
return await
|
|
37
|
+
return await loadUrlContent(url, false, true);
|
|
37
38
|
}
|
|
38
39
|
case "follow": {
|
|
39
40
|
const linkNum = parseInt(argParams[1]);
|
|
@@ -41,13 +42,13 @@ export async function handleCommand(cmdArgs) {
|
|
|
41
42
|
if (!linkUrl) {
|
|
42
43
|
return "Link number not found";
|
|
43
44
|
}
|
|
44
|
-
return await
|
|
45
|
+
return await loadUrlContent(linkUrl, true, false);
|
|
45
46
|
}
|
|
46
47
|
case "links": {
|
|
47
48
|
const url = argParams[1];
|
|
48
49
|
const isNumber = !isNaN(parseInt(argParams[2]));
|
|
49
50
|
const pageNumber = isNumber ? parseInt(argParams[2]) : 1;
|
|
50
|
-
return await
|
|
51
|
+
return await loadUrlLinks(url, pageNumber);
|
|
51
52
|
}
|
|
52
53
|
// Secret command to toggle debug mode
|
|
53
54
|
case "debug":
|
|
@@ -58,17 +59,63 @@ export async function handleCommand(cmdArgs) {
|
|
|
58
59
|
(await handleCommand("help")));
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
|
-
|
|
62
|
+
/** The content here is not reduced by an LLM, just a paged list of global links is returned */
|
|
63
|
+
async function loadUrlLinks(url, linkPageAsContent) {
|
|
62
64
|
let content = await runLynx(url);
|
|
63
65
|
let links = "";
|
|
64
66
|
// Reverse find 'References: ' and cut everything after it from the content
|
|
65
67
|
const refPos = content.lastIndexOf("References\n");
|
|
68
|
+
if (refPos > 0) {
|
|
69
|
+
links = content.slice(refPos);
|
|
70
|
+
content = "";
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
return "No Links Found";
|
|
74
|
+
}
|
|
75
|
+
// Iterate links and de-duplicate
|
|
76
|
+
const linkLines = links.split("\n");
|
|
77
|
+
const linkSet = new Set();
|
|
78
|
+
for (const linkLine of linkLines) {
|
|
79
|
+
const dotPos = linkLine.indexOf(".");
|
|
80
|
+
if (dotPos < 0) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const url = linkLine.substring(dotPos + 1).trim();
|
|
84
|
+
if (!linkSet.has(url)) {
|
|
85
|
+
linkSet.add(url);
|
|
86
|
+
content += url + "\n";
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Get the token size of the output
|
|
90
|
+
const linksTokenSize = utilities.getTokenCount(content);
|
|
91
|
+
outputInDebugMode(`Links Token size: ${linksTokenSize}`);
|
|
92
|
+
// Reduce content using LLM if it's over the token max
|
|
93
|
+
if (linksTokenSize > config.webTokenMax) {
|
|
94
|
+
content = await reduceContent(url, content, linksTokenSize, linkPageAsContent);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
output.comment(`Link Content is already under ${config.webTokenMax} tokens.`);
|
|
98
|
+
content = globalizeLinkList(content);
|
|
99
|
+
}
|
|
100
|
+
return content;
|
|
101
|
+
}
|
|
102
|
+
async function loadUrlContent(url, showUrl, showFollowHint) {
|
|
103
|
+
const originalContent = await runLynx(url);
|
|
104
|
+
let content = originalContent;
|
|
105
|
+
let links = "";
|
|
106
|
+
// Reverse find 'References: ' and cut everything after it from the content
|
|
107
|
+
const refPos = content.lastIndexOf("References\n");
|
|
66
108
|
if (refPos > 0) {
|
|
67
109
|
links = content.slice(refPos);
|
|
68
110
|
content = content.slice(0, refPos);
|
|
69
111
|
}
|
|
70
|
-
|
|
71
|
-
|
|
112
|
+
let usingCachedContent = false;
|
|
113
|
+
if (_contentCache.has(url)) {
|
|
114
|
+
const cachedContent = _contentCache.get(url);
|
|
115
|
+
if (cachedContent.originalContent === originalContent) {
|
|
116
|
+
content = cachedContent.reducedContent;
|
|
117
|
+
usingCachedContent = true;
|
|
118
|
+
}
|
|
72
119
|
}
|
|
73
120
|
// Get the token size of the output
|
|
74
121
|
const contentTokenSize = utilities.getTokenCount(content);
|
|
@@ -76,38 +123,15 @@ async function loadUrl(url, showUrl, showFollowHint, linkPageAsContent) {
|
|
|
76
123
|
outputInDebugMode(`Content Token size: ${contentTokenSize}\n` +
|
|
77
124
|
`Links Token size: ${linksTokenSize}`);
|
|
78
125
|
// Reduce content using LLM if it's over the token max
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const pieceCount = Math.ceil(contentTokenSize / tokenChunkSize);
|
|
89
|
-
const pieceSize = content.length / pieceCount;
|
|
90
|
-
let reducedOutput = "";
|
|
91
|
-
for (let i = 0; i < pieceCount; i++) {
|
|
92
|
-
const startPos = i * pieceSize;
|
|
93
|
-
const pieceStr = content.substring(startPos, startPos + pieceSize);
|
|
94
|
-
if (linkPageAsContent) {
|
|
95
|
-
if (linkPageAsContent === i + 1) {
|
|
96
|
-
return formatLinkPiece(pieceStr);
|
|
97
|
-
}
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
output.comment(`Processing Piece ${i + 1} of ${pieceCount} with ${model.key}...`);
|
|
101
|
-
outputInDebugMode(` Reduced output tokens: ${utilities.getTokenCount(reducedOutput)}\n` +
|
|
102
|
-
` Current Piece tokens: ${utilities.getTokenCount(pieceStr)}`);
|
|
103
|
-
reducedOutput = await llmReduce(url, reducedOutput, i + 1, pieceCount, pieceStr);
|
|
104
|
-
}
|
|
105
|
-
if (linkPageAsContent) {
|
|
106
|
-
return "";
|
|
107
|
-
}
|
|
108
|
-
content = reducedOutput;
|
|
109
|
-
const finalTokenSize = utilities.getTokenCount(reducedOutput);
|
|
110
|
-
output.comment(`Content reduced from ${contentTokenSize} to ${finalTokenSize} tokens`);
|
|
126
|
+
if (usingCachedContent) {
|
|
127
|
+
output.comment("No changes detected, using already cached reduced content");
|
|
128
|
+
}
|
|
129
|
+
else if (contentTokenSize > config.webTokenMax) {
|
|
130
|
+
content = await reduceContent(url, content, contentTokenSize);
|
|
131
|
+
_contentCache.set(url, {
|
|
132
|
+
originalContent,
|
|
133
|
+
reducedContent: content,
|
|
134
|
+
});
|
|
111
135
|
}
|
|
112
136
|
else {
|
|
113
137
|
output.comment(`Content is already under ${config.webTokenMax} tokens.`);
|
|
@@ -144,21 +168,55 @@ async function runLynx(url) {
|
|
|
144
168
|
});
|
|
145
169
|
});
|
|
146
170
|
}
|
|
171
|
+
async function reduceContent(url, content, contentTokenSize, linkPageAsContent) {
|
|
172
|
+
const model = getLLModel(config.agent.webModel);
|
|
173
|
+
// For example if context is 16k, and max tokens is 2k, 3k with 1.5x overrun
|
|
174
|
+
// That would be 3k for the current compressed content, 10k for the chunk, and 3k for the output
|
|
175
|
+
let tokenChunkSize = model.maxTokens - config.webTokenMax * 2 * 1.5;
|
|
176
|
+
if (linkPageAsContent) {
|
|
177
|
+
tokenChunkSize = config.webTokenMax;
|
|
178
|
+
}
|
|
179
|
+
outputInDebugMode(`Token max chunk size: ${tokenChunkSize}`);
|
|
180
|
+
const pieceCount = Math.ceil(contentTokenSize / tokenChunkSize);
|
|
181
|
+
const pieceSize = content.length / pieceCount;
|
|
182
|
+
let reducedOutput = "";
|
|
183
|
+
for (let i = 0; i < pieceCount; i++) {
|
|
184
|
+
const startPos = i * pieceSize;
|
|
185
|
+
const pieceStr = content.substring(startPos, startPos + pieceSize);
|
|
186
|
+
if (linkPageAsContent) {
|
|
187
|
+
if (linkPageAsContent === i + 1) {
|
|
188
|
+
return globalizeLinkList(pieceStr);
|
|
189
|
+
}
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
output.comment(`Processing Piece ${i + 1} of ${pieceCount} with ${model.key}...`);
|
|
193
|
+
outputInDebugMode(` Reduced output tokens: ${utilities.getTokenCount(reducedOutput)}\n` +
|
|
194
|
+
` Current Piece tokens: ${utilities.getTokenCount(pieceStr)}`);
|
|
195
|
+
reducedOutput = await llmReduce(url, reducedOutput, i + 1, pieceCount, pieceStr);
|
|
196
|
+
}
|
|
197
|
+
if (linkPageAsContent) {
|
|
198
|
+
return "";
|
|
199
|
+
}
|
|
200
|
+
const finalTokenSize = utilities.getTokenCount(reducedOutput);
|
|
201
|
+
output.comment(`Content reduced from ${contentTokenSize} to ${finalTokenSize} tokens`);
|
|
202
|
+
return reducedOutput;
|
|
203
|
+
}
|
|
147
204
|
async function llmReduce(url, reducedOutput, pieceNumber, pieceTotal, pieceStr) {
|
|
148
|
-
const systemMessage = `You will be iteratively fed the web page ${url} broken into ${pieceTotal}
|
|
149
|
-
Each
|
|
205
|
+
const systemMessage = `You will be iteratively fed the web page "${url}" broken into ${pieceTotal} pieces.
|
|
206
|
+
Each 'Web Page Piece' should be merged with the in order 'Current Reduced Content' to maintain the meaning of the page while reducing verbosity and duplication.
|
|
150
207
|
The final output should be around ${config.webTokenMax} tokens.
|
|
151
|
-
|
|
208
|
+
Links are represented as numbers in brackets, for example [4]. Try not to remove them in the 'Final Merged Content'
|
|
152
209
|
Try to prioritize content of substance over advertising content.`;
|
|
153
|
-
const content = `Web
|
|
210
|
+
const content = `Web Page Piece ${pieceNumber} of ${pieceTotal}:
|
|
154
211
|
${pieceStr}
|
|
155
212
|
|
|
156
|
-
Current
|
|
213
|
+
Please merge the 'Web Page Piece' above into the 'Current Reduced Content' below while keeping the result to around ${config.webTokenMax} tokens.
|
|
214
|
+
|
|
215
|
+
Current Reduced Content:
|
|
157
216
|
${reducedOutput}
|
|
158
217
|
|
|
159
|
-
Please merge the new piece into the existing reduced content above while keeping the result to around ${config.webTokenMax} tokens.
|
|
160
218
|
|
|
161
|
-
Merged
|
|
219
|
+
Final Merged Content:
|
|
162
220
|
`;
|
|
163
221
|
const context = {
|
|
164
222
|
role: LlmRole.User,
|
|
@@ -207,23 +265,19 @@ function registerUrl(url) {
|
|
|
207
265
|
}
|
|
208
266
|
return globalLinkNum;
|
|
209
267
|
}
|
|
210
|
-
function
|
|
268
|
+
function globalizeLinkList(pieceStr) {
|
|
211
269
|
const alreadySeen = new Set();
|
|
212
270
|
const linkLines = pieceStr.split("\n");
|
|
213
|
-
let
|
|
271
|
+
let globalLinks = "";
|
|
214
272
|
for (const linkLine of linkLines) {
|
|
215
|
-
const
|
|
216
|
-
if (
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
const url = linkLine.substring(dotPos + 1).trim();
|
|
220
|
-
if (alreadySeen.has(url)) {
|
|
273
|
+
const url = linkLine.trim();
|
|
274
|
+
if (!url || alreadySeen.has(url)) {
|
|
221
275
|
continue;
|
|
222
276
|
}
|
|
223
277
|
alreadySeen.add(url);
|
|
224
278
|
const globalLinkNum = registerUrl(url);
|
|
225
|
-
|
|
279
|
+
globalLinks += `[${globalLinkNum}]${url}\n`;
|
|
226
280
|
}
|
|
227
|
-
return
|
|
281
|
+
return globalLinks;
|
|
228
282
|
}
|
|
229
283
|
//# sourceMappingURL=llmynx.js.map
|
|
@@ -5,9 +5,9 @@ import * as config from "../config.js";
|
|
|
5
5
|
import * as contextManager from "../llm/contextManager.js";
|
|
6
6
|
import { ContentSource } from "../llm/contextManager.js";
|
|
7
7
|
import * as costTracker from "../llm/costTracker.js";
|
|
8
|
+
import * as dreamMaker from "../llm/dreamMaker.js";
|
|
8
9
|
import * as inputMode from "../utils/inputMode.js";
|
|
9
10
|
import { InputMode } from "../utils/inputMode.js";
|
|
10
|
-
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";
|
|
@@ -20,7 +20,6 @@ export var NextCommandAction;
|
|
|
20
20
|
NextCommandAction[NextCommandAction["EndSession"] = 1] = "EndSession";
|
|
21
21
|
NextCommandAction[NextCommandAction["ExitApplication"] = 2] = "ExitApplication";
|
|
22
22
|
})(NextCommandAction || (NextCommandAction = {}));
|
|
23
|
-
export let previousSessionNotes = await logService.getPreviousEndSessionNote();
|
|
24
23
|
export async function processCommand(prompt, consoleInput) {
|
|
25
24
|
// We process the lines one at a time so we can support multiple commands with line breaks
|
|
26
25
|
let firstLine = true;
|
|
@@ -67,11 +66,12 @@ export async function processCommand(prompt, consoleInput) {
|
|
|
67
66
|
}
|
|
68
67
|
case "endsession": {
|
|
69
68
|
// Don't need to check end line as this is the last command in the context, just read to the end
|
|
70
|
-
|
|
71
|
-
if (!
|
|
69
|
+
const endSessionNotes = utilities.trimChars(cmdArgs, '"');
|
|
70
|
+
if (!endSessionNotes) {
|
|
72
71
|
await contextManager.append(`End session notes are required. Use endsession "<notes>"`);
|
|
73
72
|
break;
|
|
74
73
|
}
|
|
74
|
+
await dreamMaker.goodnight();
|
|
75
75
|
await output.commentAndLog("------------------------------------------------------");
|
|
76
76
|
nextCommandAction = NextCommandAction.EndSession;
|
|
77
77
|
processNextLLMpromptBlock = false;
|
|
@@ -5,6 +5,7 @@ import * as llmynx from "../apps/llmynx.js";
|
|
|
5
5
|
import * as config from "../config.js";
|
|
6
6
|
import * as contextManager from "../llm/contextManager.js";
|
|
7
7
|
import { ContentSource } from "../llm/contextManager.js";
|
|
8
|
+
import * as dreamMaker from "../llm/dreamMaker.js";
|
|
8
9
|
import { LlmRole } from "../llm/llmDtos.js";
|
|
9
10
|
import * as llmService from "../llm/llmService.js";
|
|
10
11
|
import * as inputMode from "../utils/inputMode.js";
|
|
@@ -33,8 +34,11 @@ export async function run() {
|
|
|
33
34
|
while (nextCommandAction != NextCommandAction.ExitApplication) {
|
|
34
35
|
inputMode.toggle(InputMode.LLM);
|
|
35
36
|
await output.commentAndLog("Starting Context:");
|
|
36
|
-
await
|
|
37
|
-
|
|
37
|
+
const latestDream = await dreamMaker.goodmorning();
|
|
38
|
+
if (latestDream) {
|
|
39
|
+
await contextManager.append("Previous Session Notes:");
|
|
40
|
+
await contextManager.append(latestDream);
|
|
41
|
+
}
|
|
38
42
|
for (const initialCommand of config.agent.initialCommands) {
|
|
39
43
|
await commandHandler.processCommand(await promptBuilder.getPrompt(0, false), config.resolveConfigVars(initialCommand));
|
|
40
44
|
}
|
package/dist/config.js
CHANGED
|
@@ -29,7 +29,6 @@ function loadAgentConfig() {
|
|
|
29
29
|
"username",
|
|
30
30
|
"title",
|
|
31
31
|
"shellModel",
|
|
32
|
-
"webModel",
|
|
33
32
|
"agentPrompt",
|
|
34
33
|
"spendLimitDollars",
|
|
35
34
|
"tokenMax",
|
|
@@ -50,6 +49,8 @@ function loadAgentConfig() {
|
|
|
50
49
|
? Number(config.debugPauseSeconds)
|
|
51
50
|
: 0;
|
|
52
51
|
config.wakeOnMessage = Boolean(config.wakeOnMessage);
|
|
52
|
+
config.webModel || (config.webModel = config.shellModel);
|
|
53
|
+
config.dreamModel || (config.dreamModel = config.shellModel);
|
|
53
54
|
if (!config.commandProtection) {
|
|
54
55
|
config.commandProtection = CommandProtection.None;
|
|
55
56
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as config from "../config.js";
|
|
2
|
+
import * as dbUtils from "../utils/dbUtils.js";
|
|
3
|
+
import * as output from "../utils/output.js";
|
|
4
|
+
import { naisysToHostPath } from "../utils/utilities.js";
|
|
5
|
+
import * as contextManager from "./contextManager.js";
|
|
6
|
+
import { LlmRole } from "./llmDtos.js";
|
|
7
|
+
import * as llmService from "./llmService.js";
|
|
8
|
+
const _dbFilePath = naisysToHostPath(`${config.naisysFolder}/lib/dream.db`);
|
|
9
|
+
await init();
|
|
10
|
+
async function init() {
|
|
11
|
+
const newDbCreated = await dbUtils.initDatabase(_dbFilePath);
|
|
12
|
+
await usingDatabase(async (db) => {
|
|
13
|
+
if (!newDbCreated) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
await db.exec(`CREATE TABLE DreamLog (
|
|
17
|
+
id INTEGER PRIMARY KEY,
|
|
18
|
+
username TEXT NOT NULL,
|
|
19
|
+
date TEXT NOT NULL,
|
|
20
|
+
dream TEXT NOT NULL
|
|
21
|
+
)`);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
export async function goodmorning() {
|
|
25
|
+
return await usingDatabase(async (db) => {
|
|
26
|
+
const row = await db.get(`SELECT dream
|
|
27
|
+
FROM DreamLog
|
|
28
|
+
WHERE username = ?
|
|
29
|
+
ORDER BY date DESC LIMIT 1`, config.agent.username);
|
|
30
|
+
return row === null || row === void 0 ? void 0 : row.dream;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
export async function goodnight() {
|
|
34
|
+
output.comment("Dreaming about the session...");
|
|
35
|
+
const dream = await runDreamSequence();
|
|
36
|
+
await storeDream(dream);
|
|
37
|
+
return dream;
|
|
38
|
+
}
|
|
39
|
+
async function runDreamSequence() {
|
|
40
|
+
const systemMessage = `You are ${config.agent.username}'s unconcious sleep process. You compile all ${config.agent.username}'s
|
|
41
|
+
thoughts during the day and reduce them down to important things to remember - references, plans, project structure, schemas,
|
|
42
|
+
file locations, urls, and more. You are the sleep process, and you are the most important process. Using your results,
|
|
43
|
+
when ${config.agent.username} wakes up they'll know exactly what to do and how to do it.`;
|
|
44
|
+
const allTheThings = contextManager.messages.map((m) => m.content).join("\n");
|
|
45
|
+
return await llmService.query(config.agent.dreamModel, systemMessage, [
|
|
46
|
+
{
|
|
47
|
+
role: LlmRole.User,
|
|
48
|
+
content: allTheThings,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
role: LlmRole.Assistant,
|
|
52
|
+
content: "We sure had an eventful day",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
role: LlmRole.User,
|
|
56
|
+
content: `Dream on all these things and let me know what you come up with. Use what was done in the previous session as a guide
|
|
57
|
+
for what's possible tomorrow. Don't overload yourself with too many thoughts and ideas. Keep important references for the future
|
|
58
|
+
but don't go into any great detail of future plans unless it's happening soon. `,
|
|
59
|
+
},
|
|
60
|
+
], "dream");
|
|
61
|
+
}
|
|
62
|
+
async function usingDatabase(run) {
|
|
63
|
+
return dbUtils.usingDatabase(_dbFilePath, run);
|
|
64
|
+
}
|
|
65
|
+
async function storeDream(dream) {
|
|
66
|
+
await usingDatabase(async (db) => {
|
|
67
|
+
await db.run(`INSERT INTO DreamLog (username, date, dream)
|
|
68
|
+
VALUES (?, datetime('now'), ?)`, config.agent.username, dream);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=dreamMaker.js.map
|
package/dist/utils/logService.js
CHANGED
|
@@ -87,19 +87,6 @@ function appendToLogFile(filepath, message) {
|
|
|
87
87
|
</td>
|
|
88
88
|
</tr>`);
|
|
89
89
|
}
|
|
90
|
-
export function getPreviousEndSessionNote() {
|
|
91
|
-
// Find the most recent message in the log that starts with 'endsession' for the local user
|
|
92
|
-
return usingDatabase(async (db) => {
|
|
93
|
-
const result = await db.get(`SELECT message
|
|
94
|
-
FROM ContextLog
|
|
95
|
-
WHERE username = ? AND message LIKE 'endsession %'
|
|
96
|
-
ORDER BY id DESC
|
|
97
|
-
LIMIT 1`, [config.agent.username]);
|
|
98
|
-
const endSessionMsg = result === null || result === void 0 ? void 0 : result.message;
|
|
99
|
-
// Trim endsession prefix
|
|
100
|
-
return (endSessionMsg === null || endSessionMsg === void 0 ? void 0 : endSessionMsg.slice("endsession ".length)) || "";
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
90
|
async function usingDatabase(run) {
|
|
104
91
|
return dbUtils.usingDatabase(_dbFilePath, run);
|
|
105
92
|
}
|
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.
|
|
4
|
+
"version": "1.3.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/naisys.js",
|
|
7
7
|
"preferGlobal": true,
|
|
8
8
|
"bin": {
|
|
9
|
-
"naisys": "
|
|
9
|
+
"naisys": "bin/naisys"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"compile/run/attachable": "tsc && node --inspect dist/naisys.js ./agents/webdev-fansite.yaml",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
13
|
+
"agent:dev": "node dist/naisys.js ./agents/3-team-dev-db-content/dev.yaml",
|
|
14
|
+
"agent:db": "node dist/naisys.js ./agents/3-team-dev-db-content/db.yaml",
|
|
15
|
+
"agent:content": "node dist/naisys.js ./agents/3-team-dev-db-content/content.yaml",
|
|
15
16
|
"clean": "rm -rf dist",
|
|
16
|
-
"compile": "tsc
|
|
17
|
+
"compile": "tsc",
|
|
17
18
|
"eslint": "npx eslint --rulesdir eslint-rules src",
|
|
18
19
|
"test": "tsc && node --experimental-vm-modules node_modules/jest/bin/jest.js --testPathPattern=dist/__tests__",
|
|
19
20
|
"prettier": "npx prettier --write .",
|
|
20
21
|
"dependency-graph": "madge --image dependency-graph.png dist",
|
|
21
22
|
"detect-cycles": "madge --circular dist",
|
|
22
23
|
"updates:check": "npm-check-updates",
|
|
23
|
-
"updates:apply": "npm-check-updates -u && npm
|
|
24
|
-
"npm:publish:dryrun": "npm run clean && npm run compile && npm publish --dry-run",
|
|
24
|
+
"updates:apply": "npm-check-updates -u && npm install",
|
|
25
|
+
"npm:publish:dryrun": "npm run clean && npm install && npm run compile && npm publish --dry-run",
|
|
25
26
|
"postinstall": "chmod +x ./bin/*"
|
|
26
27
|
},
|
|
27
28
|
"repository": {
|
|
@@ -42,7 +43,7 @@
|
|
|
42
43
|
"devDependencies": {
|
|
43
44
|
"@types/escape-html": "1.0.4",
|
|
44
45
|
"@types/js-yaml": "4.0.9",
|
|
45
|
-
"@types/node": "20.11.
|
|
46
|
+
"@types/node": "20.11.28",
|
|
46
47
|
"@types/text-table": "0.2.5",
|
|
47
48
|
"@typescript-eslint/eslint-plugin": "7.2.0",
|
|
48
49
|
"@typescript-eslint/parser": "7.2.0",
|
|
@@ -53,14 +54,14 @@
|
|
|
53
54
|
"typescript": "5.4.2"
|
|
54
55
|
},
|
|
55
56
|
"dependencies": {
|
|
56
|
-
"@anthropic-ai/sdk": "0.
|
|
57
|
+
"@anthropic-ai/sdk": "0.18.0",
|
|
57
58
|
"@google/generative-ai": "0.3.0",
|
|
58
59
|
"chalk": "5.3.0",
|
|
59
60
|
"commander": "12.0.0",
|
|
60
61
|
"dotenv": "16.4.5",
|
|
61
62
|
"escape-html": "1.0.3",
|
|
62
63
|
"js-yaml": "4.1.0",
|
|
63
|
-
"openai": "4.
|
|
64
|
+
"openai": "4.29.0",
|
|
64
65
|
"sqlite": "5.1.1",
|
|
65
66
|
"sqlite3": "5.1.7",
|
|
66
67
|
"text-table": "0.2.0",
|