igris-soul 1.1.0 → 1.1.2
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/cli.cjs +23 -0
- package/index.js +130 -74
- package/package.json +9 -7
package/cli.cjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawn } = require("node:child_process");
|
|
4
|
+
const { fileURLToPath } = require("node:url");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
|
|
7
|
+
const packageDir = path.dirname(
|
|
8
|
+
fileURLToPath(require.resolve("./package.json")),
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const indexPath = path.join(packageDir, "index.js");
|
|
12
|
+
|
|
13
|
+
const child = spawn(process.execPath, [indexPath, ...process.argv.slice(2)], {
|
|
14
|
+
stdio: "inherit",
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
child.on("exit", (code, signal) => {
|
|
18
|
+
if (signal) {
|
|
19
|
+
process.kill(process.pid, signal);
|
|
20
|
+
} else {
|
|
21
|
+
process.exit(code ?? 0);
|
|
22
|
+
}
|
|
23
|
+
});
|
package/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import rl from "readline/promises";
|
|
13
|
+
|
|
13
14
|
import {
|
|
14
15
|
HumanMessage,
|
|
15
16
|
AIMessage,
|
|
@@ -18,81 +19,102 @@ import {
|
|
|
18
19
|
createAgent,
|
|
19
20
|
AIMessageChunk,
|
|
20
21
|
} from "langchain";
|
|
22
|
+
|
|
21
23
|
import * as z from "zod";
|
|
22
24
|
|
|
23
25
|
/* =========================================================
|
|
24
|
-
IGRIS
|
|
26
|
+
IGRIS DIRECTORIES & FILES
|
|
25
27
|
========================================================= */
|
|
26
28
|
|
|
27
29
|
const igrisDir = join(homedir(), ".igris");
|
|
28
30
|
const envPath = join(igrisDir, ".env");
|
|
29
31
|
const userDataPath = join(igrisDir, "user.json");
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
/* =========================================================
|
|
34
|
+
READLINE
|
|
35
|
+
========================================================= */
|
|
36
|
+
|
|
37
|
+
const readline = rl.createInterface({
|
|
38
|
+
input: process.stdin,
|
|
39
|
+
output: process.stdout,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
/* =========================================================
|
|
43
|
+
CREATE IGRIS DIRECTORY
|
|
44
|
+
========================================================= */
|
|
45
|
+
|
|
32
46
|
await mkdir(igrisDir, { recursive: true });
|
|
33
47
|
|
|
34
|
-
|
|
48
|
+
/* =========================================================
|
|
49
|
+
CREATE .ENV IF IT DOESN'T EXIST
|
|
50
|
+
========================================================= */
|
|
51
|
+
|
|
35
52
|
async function ensureEnvFile() {
|
|
36
53
|
try {
|
|
37
54
|
await access(envPath);
|
|
38
55
|
} catch {
|
|
39
56
|
await writeFile(
|
|
40
57
|
envPath,
|
|
41
|
-
|
|
58
|
+
"GENAI_API_KEY=\nTAVILY_API_KEY=\n",
|
|
42
59
|
"utf8",
|
|
43
60
|
);
|
|
44
|
-
|
|
45
|
-
console.log(`
|
|
46
|
-
Igris configuration created.
|
|
47
|
-
|
|
48
|
-
Configuration file:
|
|
49
|
-
${envPath}
|
|
50
|
-
|
|
51
|
-
You will now be asked for your API keys.
|
|
52
|
-
`);
|
|
53
61
|
}
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
await ensureEnvFile();
|
|
57
65
|
|
|
58
|
-
|
|
66
|
+
/* =========================================================
|
|
67
|
+
LOAD ENVIRONMENT VARIABLES
|
|
68
|
+
========================================================= */
|
|
69
|
+
|
|
59
70
|
config({
|
|
60
71
|
path: envPath,
|
|
72
|
+
override: true,
|
|
61
73
|
quiet: true,
|
|
62
74
|
});
|
|
63
75
|
|
|
64
76
|
/* =========================================================
|
|
65
|
-
|
|
77
|
+
API KEY SETUP
|
|
66
78
|
========================================================= */
|
|
67
79
|
|
|
68
80
|
async function getApiKey(variableName, displayName) {
|
|
69
81
|
let value = process.env[variableName]?.trim();
|
|
70
82
|
|
|
83
|
+
// Already configured
|
|
71
84
|
if (value) {
|
|
72
85
|
return value;
|
|
73
86
|
}
|
|
74
87
|
|
|
75
|
-
|
|
76
|
-
`${displayName}: `,
|
|
77
|
-
);
|
|
88
|
+
console.log("");
|
|
78
89
|
|
|
79
|
-
value =
|
|
90
|
+
value = (
|
|
91
|
+
await readline.question(`${displayName}: `)
|
|
92
|
+
).trim();
|
|
80
93
|
|
|
81
94
|
if (!value) {
|
|
82
|
-
console.error(
|
|
95
|
+
console.error(
|
|
96
|
+
`\n${displayName} cannot be empty.`,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
readline.close();
|
|
83
100
|
process.exit(1);
|
|
84
101
|
}
|
|
85
102
|
|
|
86
|
-
// Read existing .env
|
|
87
103
|
let envContent = "";
|
|
88
104
|
|
|
89
105
|
try {
|
|
90
|
-
envContent = await readFile(
|
|
106
|
+
envContent = await readFile(
|
|
107
|
+
envPath,
|
|
108
|
+
"utf8",
|
|
109
|
+
);
|
|
91
110
|
} catch {
|
|
92
111
|
envContent = "";
|
|
93
112
|
}
|
|
94
113
|
|
|
95
|
-
const regex = new RegExp(
|
|
114
|
+
const regex = new RegExp(
|
|
115
|
+
`^${variableName}=.*$`,
|
|
116
|
+
"m",
|
|
117
|
+
);
|
|
96
118
|
|
|
97
119
|
if (regex.test(envContent)) {
|
|
98
120
|
envContent = envContent.replace(
|
|
@@ -100,27 +122,23 @@ async function getApiKey(variableName, displayName) {
|
|
|
100
122
|
`${variableName}=${value}`,
|
|
101
123
|
);
|
|
102
124
|
} else {
|
|
103
|
-
envContent += `\n${variableName}=${value}
|
|
125
|
+
envContent += `\n${variableName}=${value}`;
|
|
104
126
|
}
|
|
105
127
|
|
|
106
|
-
await writeFile(
|
|
128
|
+
await writeFile(
|
|
129
|
+
envPath,
|
|
130
|
+
envContent.trim() + "\n",
|
|
131
|
+
"utf8",
|
|
132
|
+
);
|
|
107
133
|
|
|
134
|
+
// Make it immediately available to process.env
|
|
108
135
|
process.env[variableName] = value;
|
|
109
136
|
|
|
110
137
|
return value;
|
|
111
138
|
}
|
|
112
139
|
|
|
113
140
|
/* =========================================================
|
|
114
|
-
|
|
115
|
-
========================================================= */
|
|
116
|
-
|
|
117
|
-
const readline = rl.createInterface({
|
|
118
|
-
input: process.stdin,
|
|
119
|
-
output: process.stdout,
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
/* =========================================================
|
|
123
|
-
API CONFIGURATION
|
|
141
|
+
GET REQUIRED API KEYS
|
|
124
142
|
========================================================= */
|
|
125
143
|
|
|
126
144
|
const genaiApiKey = await getApiKey(
|
|
@@ -141,7 +159,11 @@ const tavly = tavily({
|
|
|
141
159
|
apiKey: tavilyApiKey,
|
|
142
160
|
});
|
|
143
161
|
|
|
144
|
-
|
|
162
|
+
/* =========================================================
|
|
163
|
+
LATEST INFORMATION TOOL
|
|
164
|
+
========================================================= */
|
|
165
|
+
|
|
166
|
+
async function getLatestInfos({ query }) {
|
|
145
167
|
const response = await tavly.search(query, {
|
|
146
168
|
searchDepth: "fast",
|
|
147
169
|
maxResults: 3,
|
|
@@ -150,52 +172,70 @@ async function getLetestInfos({ query }) {
|
|
|
150
172
|
|
|
151
173
|
const results = response.results;
|
|
152
174
|
|
|
153
|
-
|
|
175
|
+
return results
|
|
154
176
|
.map((result) => result.content)
|
|
155
177
|
.join("\n\n");
|
|
156
|
-
|
|
157
|
-
return content;
|
|
158
178
|
}
|
|
159
179
|
|
|
160
|
-
const getLatestInfosTool = tool(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
180
|
+
const getLatestInfosTool = tool(
|
|
181
|
+
getLatestInfos,
|
|
182
|
+
{
|
|
183
|
+
name: "get_latest_infos",
|
|
184
|
+
|
|
185
|
+
description:
|
|
186
|
+
"Get the latest updates from India, including news, policies, and stock market trends.",
|
|
187
|
+
|
|
188
|
+
schema: z.object({
|
|
189
|
+
query: z
|
|
190
|
+
.string()
|
|
191
|
+
.describe(
|
|
192
|
+
"The query for which you want to get the latest updates from India.",
|
|
193
|
+
),
|
|
194
|
+
}),
|
|
195
|
+
},
|
|
196
|
+
);
|
|
172
197
|
|
|
173
198
|
/* =========================================================
|
|
174
|
-
USER
|
|
199
|
+
USER NAME
|
|
175
200
|
========================================================= */
|
|
176
201
|
|
|
177
202
|
async function getUserName() {
|
|
178
203
|
try {
|
|
179
204
|
const userData = JSON.parse(
|
|
180
|
-
await readFile(
|
|
205
|
+
await readFile(
|
|
206
|
+
userDataPath,
|
|
207
|
+
"utf8",
|
|
208
|
+
),
|
|
181
209
|
);
|
|
182
210
|
|
|
183
|
-
|
|
211
|
+
if (userData.name?.trim()) {
|
|
212
|
+
return userData.name.trim();
|
|
213
|
+
}
|
|
184
214
|
} catch {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
"What is your name, My Lord? ",
|
|
188
|
-
)
|
|
189
|
-
).trim();
|
|
215
|
+
// User data doesn't exist yet.
|
|
216
|
+
}
|
|
190
217
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
218
|
+
const name = (
|
|
219
|
+
await readline.question(
|
|
220
|
+
"What is your name, My Lord? ",
|
|
221
|
+
)
|
|
222
|
+
).trim();
|
|
196
223
|
|
|
197
|
-
|
|
224
|
+
if (!name) {
|
|
225
|
+
return "My Lord";
|
|
198
226
|
}
|
|
227
|
+
|
|
228
|
+
await writeFile(
|
|
229
|
+
userDataPath,
|
|
230
|
+
JSON.stringify(
|
|
231
|
+
{ name },
|
|
232
|
+
null,
|
|
233
|
+
2,
|
|
234
|
+
),
|
|
235
|
+
"utf8",
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
return name;
|
|
199
239
|
}
|
|
200
240
|
|
|
201
241
|
const userName = await getUserName();
|
|
@@ -244,7 +284,7 @@ Use them only when needed for styling, context, or a poetic response.
|
|
|
244
284
|
];
|
|
245
285
|
|
|
246
286
|
/* =========================================================
|
|
247
|
-
|
|
287
|
+
STARTUP MESSAGE
|
|
248
288
|
========================================================= */
|
|
249
289
|
|
|
250
290
|
console.log(`
|
|
@@ -255,6 +295,7 @@ console.log(`
|
|
|
255
295
|
|
|
256
296
|
Hi, My Lord, I am Igris, your loyal servant.
|
|
257
297
|
How may I assist you today?
|
|
298
|
+
|
|
258
299
|
`);
|
|
259
300
|
|
|
260
301
|
/* =========================================================
|
|
@@ -263,21 +304,27 @@ How may I assist you today?
|
|
|
263
304
|
|
|
264
305
|
try {
|
|
265
306
|
while (true) {
|
|
266
|
-
const prompt = await readline.question(
|
|
307
|
+
const prompt = await readline.question(
|
|
308
|
+
"You: ",
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
const trimmedPrompt = prompt.trim();
|
|
267
312
|
|
|
268
313
|
if (
|
|
269
314
|
["exit", "quit"].includes(
|
|
270
|
-
|
|
315
|
+
trimmedPrompt.toLowerCase(),
|
|
271
316
|
)
|
|
272
317
|
) {
|
|
273
318
|
break;
|
|
274
319
|
}
|
|
275
320
|
|
|
276
|
-
if (!
|
|
321
|
+
if (!trimmedPrompt) {
|
|
277
322
|
continue;
|
|
278
323
|
}
|
|
279
324
|
|
|
280
|
-
messages.push(
|
|
325
|
+
messages.push(
|
|
326
|
+
new HumanMessage(trimmedPrompt),
|
|
327
|
+
);
|
|
281
328
|
|
|
282
329
|
const stream = await agent.stream(
|
|
283
330
|
{
|
|
@@ -290,7 +337,7 @@ try {
|
|
|
290
337
|
|
|
291
338
|
let aiResponse = "";
|
|
292
339
|
|
|
293
|
-
console.log("Igris:
|
|
340
|
+
console.log("Igris:");
|
|
294
341
|
|
|
295
342
|
for await (const [chunk] of stream) {
|
|
296
343
|
if (chunk instanceof AIMessageChunk) {
|
|
@@ -299,11 +346,20 @@ try {
|
|
|
299
346
|
}
|
|
300
347
|
}
|
|
301
348
|
|
|
302
|
-
messages.push(
|
|
349
|
+
messages.push(
|
|
350
|
+
new AIMessage(aiResponse),
|
|
351
|
+
);
|
|
303
352
|
|
|
304
353
|
process.stdout.write("\n\n");
|
|
305
354
|
}
|
|
355
|
+
} catch (error) {
|
|
356
|
+
console.error(
|
|
357
|
+
"\nIgris encountered an error:",
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
console.error(
|
|
361
|
+
error?.message || error,
|
|
362
|
+
);
|
|
306
363
|
} finally {
|
|
307
364
|
readline.close();
|
|
308
|
-
}
|
|
309
|
-
|
|
365
|
+
}
|
package/package.json
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "igris-soul",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "A terminal AI assistant powered by Gemini and Tavily.",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "Barshan Majumdar",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "index.js",
|
|
9
9
|
"bin": {
|
|
10
|
-
"Arise": "
|
|
11
|
-
"arise": "
|
|
12
|
-
"igris-soul": "
|
|
13
|
-
"igris": "
|
|
10
|
+
"Arise": "cli.cjs",
|
|
11
|
+
"arise": "cli.cjs",
|
|
12
|
+
"igris-soul": "cli.cjs",
|
|
13
|
+
"igris": "cli.cjs"
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
"index.js",
|
|
17
|
+
"cli.cjs",
|
|
18
|
+
".env.example",
|
|
19
|
+
"README.md"
|
|
18
20
|
],
|
|
19
21
|
"engines": {
|
|
20
22
|
"node": ">=20"
|