igris-soul 1.0.0 → 1.1.1
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 +345 -31
- package/index.js +278 -58
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Igris Soul
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Your personal AI assistant in the terminal, inspired by Igris from Solo Leveling.
|
|
4
|
+
>
|
|
5
|
+
> Install it globally and summon Igris from anywhere:
|
|
4
6
|
>
|
|
5
7
|
> ```bash
|
|
6
8
|
> npm install -g igris-soul
|
|
@@ -9,33 +11,231 @@
|
|
|
9
11
|
|
|
10
12
|
## Disclaimer
|
|
11
13
|
|
|
12
|
-
This project sends your prompts to Google Gemini and may send web-search requests to Tavily. Do not enter passwords, private keys, personal data, confidential business information, or any other sensitive information into the assistant.
|
|
14
|
+
This project sends your prompts to Google Gemini and may send web-search requests to Tavily. Do not enter passwords, private keys, personal data, confidential business information, or any other sensitive information into the assistant.
|
|
15
|
+
|
|
16
|
+
You are responsible for reviewing generated answers and for the API usage and charges associated with your API keys.
|
|
17
|
+
|
|
18
|
+
This project is provided for educational and personal use without guarantees about accuracy, availability, or fitness for a particular purpose.
|
|
19
|
+
|
|
20
|
+
---
|
|
13
21
|
|
|
14
22
|
## Requirements
|
|
15
23
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
Before installing Igris Soul, make sure you have:
|
|
25
|
+
|
|
26
|
+
* Node.js 20 or newer
|
|
27
|
+
* A Google Gemini API key
|
|
28
|
+
* A Tavily API key for current-information searches
|
|
29
|
+
* An npm account if you want to install or publish the package through npm
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
# Installation
|
|
34
|
+
|
|
35
|
+
## Install Globally
|
|
36
|
+
|
|
37
|
+
To use Igris Soul from anywhere on your computer:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install -g igris-soul
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
After installation, start Igris with:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
Arise
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
You can run `Arise` from any directory.
|
|
50
|
+
|
|
51
|
+
For example:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
C:\Users\YourName> Arise
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
or:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
D:\Projects\MyProject> Arise
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
or:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
E:\Anything> Arise
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Igris does not depend on the directory from which you launch it.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
# First-Time Setup
|
|
74
|
+
|
|
75
|
+
On the first launch, Igris automatically creates its configuration directory in your home directory:
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
~/.igris/
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
It will automatically create:
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
~/.igris/
|
|
85
|
+
├── .env
|
|
86
|
+
└── user.json
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
You do **not** need to manually create these files.
|
|
90
|
+
|
|
91
|
+
Igris will ask for the required API keys if they are not already configured:
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
Enter your Gemini API key:
|
|
95
|
+
Enter your Tavily API key:
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The keys are then stored locally in:
|
|
19
99
|
|
|
20
|
-
|
|
100
|
+
```text
|
|
101
|
+
~/.igris/.env
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
On Windows, this is typically:
|
|
105
|
+
|
|
106
|
+
```text
|
|
107
|
+
C:\Users\YourName\.igris\.env
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Your name is stored separately in:
|
|
111
|
+
|
|
112
|
+
```text
|
|
113
|
+
C:\Users\YourName\.igris\user.json
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
On future launches, Igris automatically loads the saved configuration.
|
|
117
|
+
|
|
118
|
+
---
|
|
21
119
|
|
|
22
|
-
|
|
120
|
+
# Configuration
|
|
121
|
+
|
|
122
|
+
The automatically created `.env` file contains:
|
|
23
123
|
|
|
24
124
|
```env
|
|
25
125
|
GENAI_API_KEY=your_google_gemini_api_key
|
|
26
126
|
TAVILY_API_KEY=your_tavily_api_key
|
|
27
127
|
```
|
|
28
128
|
|
|
29
|
-
|
|
129
|
+
### Environment Variables
|
|
130
|
+
|
|
131
|
+
| Variable | Purpose |
|
|
132
|
+
| ---------------- | ------------------------------- |
|
|
133
|
+
| `GENAI_API_KEY` | Google Gemini API key |
|
|
134
|
+
| `TAVILY_API_KEY` | Tavily API key for web searches |
|
|
135
|
+
|
|
136
|
+
You can manually edit:
|
|
137
|
+
|
|
138
|
+
```text
|
|
139
|
+
~/.igris/.env
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
if you need to change your API keys.
|
|
143
|
+
|
|
144
|
+
### Security
|
|
145
|
+
|
|
146
|
+
Never commit or share your `.env` file.
|
|
147
|
+
|
|
148
|
+
Never put real API keys inside the source code.
|
|
149
|
+
|
|
150
|
+
The `.env` file contains sensitive credentials and should remain on your local machine.
|
|
151
|
+
|
|
152
|
+
The project includes `.env.example` as a safe template:
|
|
153
|
+
|
|
154
|
+
```env
|
|
155
|
+
GENAI_API_KEY=
|
|
156
|
+
TAVILY_API_KEY=
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
# Running Igris
|
|
162
|
+
|
|
163
|
+
After installation:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
Arise
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
You will see:
|
|
170
|
+
|
|
171
|
+
```text
|
|
172
|
+
+----------------------+
|
|
173
|
+
| IGRIS |
|
|
174
|
+
| AGENT ONLINE |
|
|
175
|
+
+----------------------+
|
|
176
|
+
|
|
177
|
+
Hi, My Lord, I am Igris, your loyal servant.
|
|
178
|
+
How may I assist you today?
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
You can then enter your prompts directly in the terminal.
|
|
182
|
+
|
|
183
|
+
Example:
|
|
184
|
+
|
|
185
|
+
```text
|
|
186
|
+
You: Explain binary search in Java
|
|
187
|
+
|
|
188
|
+
Igris:
|
|
189
|
+
...
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
To exit the assistant:
|
|
193
|
+
|
|
194
|
+
```text
|
|
195
|
+
exit
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
or:
|
|
199
|
+
|
|
200
|
+
```text
|
|
201
|
+
quit
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
# Features
|
|
207
|
+
|
|
208
|
+
* Interactive terminal-based AI assistant
|
|
209
|
+
* Google Gemini-powered responses
|
|
210
|
+
* Streaming AI responses
|
|
211
|
+
* Tavily web search for current information
|
|
212
|
+
* Conversation history during the current session
|
|
213
|
+
* Personalized responses using your saved name
|
|
214
|
+
* First-launch name setup
|
|
215
|
+
* Persistent configuration
|
|
216
|
+
* Automatic `.igris` directory creation
|
|
217
|
+
* Automatic `.env` creation
|
|
218
|
+
* Global CLI access
|
|
219
|
+
* Runs from any directory
|
|
220
|
+
* `Arise` command for launching the assistant
|
|
30
221
|
|
|
31
|
-
|
|
222
|
+
---
|
|
32
223
|
|
|
33
|
-
|
|
224
|
+
# Local Development
|
|
34
225
|
|
|
35
|
-
|
|
226
|
+
If you want to run Igris Soul directly from the source code instead of installing it globally:
|
|
227
|
+
|
|
228
|
+
Clone or download the repository and enter the project directory.
|
|
229
|
+
|
|
230
|
+
Install dependencies:
|
|
36
231
|
|
|
37
232
|
```bash
|
|
38
233
|
npm install
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Then start Igris:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
39
239
|
npm start
|
|
40
240
|
```
|
|
41
241
|
|
|
@@ -45,50 +245,164 @@ You can also run:
|
|
|
45
245
|
node index.js
|
|
46
246
|
```
|
|
47
247
|
|
|
48
|
-
|
|
248
|
+
The same `~/.igris/.env` configuration is used.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
# Test the Package Locally
|
|
253
|
+
|
|
254
|
+
Before publishing a new version to npm, you can test the CLI directly from the package directory.
|
|
49
255
|
|
|
50
|
-
|
|
256
|
+
Install the local package globally:
|
|
51
257
|
|
|
52
258
|
```bash
|
|
53
|
-
npm install -g
|
|
54
|
-
Arise
|
|
259
|
+
npm install -g .
|
|
55
260
|
```
|
|
56
261
|
|
|
57
|
-
|
|
262
|
+
Then run:
|
|
58
263
|
|
|
59
264
|
```bash
|
|
60
|
-
npm install -g .
|
|
61
265
|
Arise
|
|
62
266
|
```
|
|
63
267
|
|
|
64
|
-
|
|
268
|
+
This allows you to test the global CLI behavior using your local source code.
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
# Updating Igris Soul
|
|
65
273
|
|
|
66
|
-
|
|
67
|
-
- Google Gemini-powered answers
|
|
68
|
-
- Tavily web search for current information
|
|
69
|
-
- Conversation history during the current session
|
|
70
|
-
- First-launch name setup
|
|
71
|
-
- Persistent name storage in `~/.igris/user.json`
|
|
72
|
-
- `Arise`, `igris-soul`, and `igris` global commands
|
|
274
|
+
When a new version is published, update your global installation with:
|
|
73
275
|
|
|
74
|
-
|
|
276
|
+
```bash
|
|
277
|
+
npm install -g igris-soul@latest
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Your personal configuration remains outside the npm package:
|
|
281
|
+
|
|
282
|
+
```text
|
|
283
|
+
~/.igris/
|
|
284
|
+
├── .env
|
|
285
|
+
└── user.json
|
|
286
|
+
```
|
|
75
287
|
|
|
76
|
-
|
|
288
|
+
Therefore, updating the package does not require you to enter your API keys again.
|
|
77
289
|
|
|
78
|
-
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
# Uninstalling
|
|
293
|
+
|
|
294
|
+
To remove the globally installed package:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
npm uninstall -g igris-soul
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Your personal Igris configuration remains in:
|
|
301
|
+
|
|
302
|
+
```text
|
|
303
|
+
~/.igris/
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
If you want to completely remove your local Igris configuration as well, delete the `.igris` directory manually.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
# Publishing to npm
|
|
311
|
+
|
|
312
|
+
If you are the package maintainer and want to publish a new version:
|
|
313
|
+
|
|
314
|
+
First, log in to npm:
|
|
79
315
|
|
|
80
316
|
```bash
|
|
81
317
|
npm login
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Verify your account:
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
npm whoami
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Run the tests:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
82
329
|
npm test
|
|
83
|
-
npm publish
|
|
84
330
|
```
|
|
85
331
|
|
|
86
|
-
|
|
332
|
+
Check what will be included in the package:
|
|
87
333
|
|
|
88
334
|
```bash
|
|
89
335
|
npm publish --dry-run
|
|
90
336
|
```
|
|
91
337
|
|
|
92
|
-
|
|
338
|
+
If everything looks correct, publish:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
npm publish
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## Updating the Version
|
|
345
|
+
|
|
346
|
+
npm does not allow publishing the same package version twice.
|
|
347
|
+
|
|
348
|
+
For a bug fix:
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
npm version patch
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
For a new feature:
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
npm version minor
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
For a breaking change:
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
npm version major
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Then publish the new version:
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
npm publish
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Example:
|
|
373
|
+
|
|
374
|
+
```text
|
|
375
|
+
1.0.0 → 1.0.1
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
# Package Usage
|
|
381
|
+
|
|
382
|
+
Igris Soul is primarily designed as a global terminal assistant.
|
|
383
|
+
|
|
384
|
+
Install:
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
npm install -g igris-soul
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
Run:
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
Arise
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
The package is installed globally, while user-specific configuration is stored separately in:
|
|
397
|
+
|
|
398
|
+
```text
|
|
399
|
+
~/.igris/
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
This allows Igris to maintain its configuration independently of the directory from which it is launched.
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
# License
|
|
93
407
|
|
|
94
408
|
ISC
|
package/index.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
1
|
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
|
|
4
2
|
import { config } from "dotenv";
|
|
5
3
|
import { tavily } from "@tavily/core";
|
|
6
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
mkdir,
|
|
6
|
+
readFile,
|
|
7
|
+
writeFile,
|
|
8
|
+
access,
|
|
9
|
+
} from "node:fs/promises";
|
|
7
10
|
import { homedir } from "node:os";
|
|
8
11
|
import { join } from "node:path";
|
|
9
12
|
import rl from "readline/promises";
|
|
13
|
+
|
|
10
14
|
import {
|
|
11
15
|
HumanMessage,
|
|
12
16
|
AIMessage,
|
|
@@ -15,17 +19,151 @@ import {
|
|
|
15
19
|
createAgent,
|
|
16
20
|
AIMessageChunk,
|
|
17
21
|
} from "langchain";
|
|
22
|
+
|
|
18
23
|
import * as z from "zod";
|
|
19
24
|
|
|
25
|
+
/* =========================================================
|
|
26
|
+
IGRIS DIRECTORIES & FILES
|
|
27
|
+
========================================================= */
|
|
28
|
+
|
|
29
|
+
const igrisDir = join(homedir(), ".igris");
|
|
30
|
+
const envPath = join(igrisDir, ".env");
|
|
31
|
+
const userDataPath = join(igrisDir, "user.json");
|
|
32
|
+
|
|
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
|
+
|
|
46
|
+
await mkdir(igrisDir, { recursive: true });
|
|
47
|
+
|
|
48
|
+
/* =========================================================
|
|
49
|
+
CREATE .ENV IF IT DOESN'T EXIST
|
|
50
|
+
========================================================= */
|
|
51
|
+
|
|
52
|
+
async function ensureEnvFile() {
|
|
53
|
+
try {
|
|
54
|
+
await access(envPath);
|
|
55
|
+
} catch {
|
|
56
|
+
await writeFile(
|
|
57
|
+
envPath,
|
|
58
|
+
"GENAI_API_KEY=\nTAVILY_API_KEY=\n",
|
|
59
|
+
"utf8",
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
await ensureEnvFile();
|
|
65
|
+
|
|
66
|
+
/* =========================================================
|
|
67
|
+
LOAD ENVIRONMENT VARIABLES
|
|
68
|
+
========================================================= */
|
|
69
|
+
|
|
20
70
|
config({
|
|
21
|
-
path:
|
|
71
|
+
path: envPath,
|
|
72
|
+
override: true,
|
|
22
73
|
quiet: true,
|
|
23
74
|
});
|
|
75
|
+
|
|
76
|
+
/* =========================================================
|
|
77
|
+
API KEY SETUP
|
|
78
|
+
========================================================= */
|
|
79
|
+
|
|
80
|
+
async function getApiKey(variableName, displayName) {
|
|
81
|
+
let value = process.env[variableName]?.trim();
|
|
82
|
+
|
|
83
|
+
// Already configured
|
|
84
|
+
if (value) {
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
console.log("");
|
|
89
|
+
|
|
90
|
+
value = (
|
|
91
|
+
await readline.question(`${displayName}: `)
|
|
92
|
+
).trim();
|
|
93
|
+
|
|
94
|
+
if (!value) {
|
|
95
|
+
console.error(
|
|
96
|
+
`\n${displayName} cannot be empty.`,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
readline.close();
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let envContent = "";
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
envContent = await readFile(
|
|
107
|
+
envPath,
|
|
108
|
+
"utf8",
|
|
109
|
+
);
|
|
110
|
+
} catch {
|
|
111
|
+
envContent = "";
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const regex = new RegExp(
|
|
115
|
+
`^${variableName}=.*$`,
|
|
116
|
+
"m",
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
if (regex.test(envContent)) {
|
|
120
|
+
envContent = envContent.replace(
|
|
121
|
+
regex,
|
|
122
|
+
`${variableName}=${value}`,
|
|
123
|
+
);
|
|
124
|
+
} else {
|
|
125
|
+
envContent += `\n${variableName}=${value}`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
await writeFile(
|
|
129
|
+
envPath,
|
|
130
|
+
envContent.trim() + "\n",
|
|
131
|
+
"utf8",
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
// Make it immediately available to process.env
|
|
135
|
+
process.env[variableName] = value;
|
|
136
|
+
|
|
137
|
+
return value;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* =========================================================
|
|
141
|
+
GET REQUIRED API KEYS
|
|
142
|
+
========================================================= */
|
|
143
|
+
|
|
144
|
+
const genaiApiKey = await getApiKey(
|
|
145
|
+
"GENAI_API_KEY",
|
|
146
|
+
"Enter your Gemini API key",
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const tavilyApiKey = await getApiKey(
|
|
150
|
+
"TAVILY_API_KEY",
|
|
151
|
+
"Enter your Tavily API key",
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
/* =========================================================
|
|
155
|
+
TAVILY
|
|
156
|
+
========================================================= */
|
|
157
|
+
|
|
24
158
|
const tavly = tavily({
|
|
25
|
-
apiKey:
|
|
159
|
+
apiKey: tavilyApiKey,
|
|
26
160
|
});
|
|
27
|
-
|
|
28
|
-
|
|
161
|
+
|
|
162
|
+
/* =========================================================
|
|
163
|
+
LATEST INFORMATION TOOL
|
|
164
|
+
========================================================= */
|
|
165
|
+
|
|
166
|
+
async function getLatestInfos({ query }) {
|
|
29
167
|
const response = await tavly.search(query, {
|
|
30
168
|
searchDepth: "fast",
|
|
31
169
|
maxResults: 3,
|
|
@@ -33,94 +171,161 @@ async function getLetestInfos({ query }) {
|
|
|
33
171
|
});
|
|
34
172
|
|
|
35
173
|
const results = response.results;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
174
|
+
|
|
175
|
+
return results
|
|
176
|
+
.map((result) => result.content)
|
|
177
|
+
.join("\n\n");
|
|
39
178
|
}
|
|
40
179
|
|
|
41
|
-
const getLatestInfosTool = tool(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
schema: z.object({
|
|
46
|
-
query: z
|
|
47
|
-
.string()
|
|
48
|
-
.describe(
|
|
49
|
-
"The query for which you want to get the latest updates from India.",
|
|
50
|
-
),
|
|
51
|
-
}),
|
|
52
|
-
});
|
|
180
|
+
const getLatestInfosTool = tool(
|
|
181
|
+
getLatestInfos,
|
|
182
|
+
{
|
|
183
|
+
name: "get_latest_infos",
|
|
53
184
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
+
);
|
|
58
197
|
|
|
59
|
-
|
|
198
|
+
/* =========================================================
|
|
199
|
+
USER NAME
|
|
200
|
+
========================================================= */
|
|
60
201
|
|
|
61
202
|
async function getUserName() {
|
|
62
203
|
try {
|
|
63
|
-
const userData = JSON.parse(
|
|
64
|
-
|
|
204
|
+
const userData = JSON.parse(
|
|
205
|
+
await readFile(
|
|
206
|
+
userDataPath,
|
|
207
|
+
"utf8",
|
|
208
|
+
),
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
if (userData.name?.trim()) {
|
|
212
|
+
return userData.name.trim();
|
|
213
|
+
}
|
|
65
214
|
} catch {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
await
|
|
71
|
-
|
|
215
|
+
// User data doesn't exist yet.
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const name = (
|
|
219
|
+
await readline.question(
|
|
220
|
+
"What is your name, My Lord? ",
|
|
221
|
+
)
|
|
222
|
+
).trim();
|
|
223
|
+
|
|
224
|
+
if (!name) {
|
|
225
|
+
return "My Lord";
|
|
72
226
|
}
|
|
227
|
+
|
|
228
|
+
await writeFile(
|
|
229
|
+
userDataPath,
|
|
230
|
+
JSON.stringify(
|
|
231
|
+
{ name },
|
|
232
|
+
null,
|
|
233
|
+
2,
|
|
234
|
+
),
|
|
235
|
+
"utf8",
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
return name;
|
|
73
239
|
}
|
|
74
240
|
|
|
75
241
|
const userName = await getUserName();
|
|
76
242
|
|
|
243
|
+
/* =========================================================
|
|
244
|
+
GEMINI MODEL
|
|
245
|
+
========================================================= */
|
|
246
|
+
|
|
77
247
|
const model = new ChatGoogleGenerativeAI({
|
|
78
248
|
model: "gemini-3.5-flash-lite",
|
|
79
|
-
apiKey:
|
|
249
|
+
apiKey: genaiApiKey,
|
|
80
250
|
});
|
|
81
251
|
|
|
252
|
+
/* =========================================================
|
|
253
|
+
AGENT
|
|
254
|
+
========================================================= */
|
|
255
|
+
|
|
82
256
|
const agent = createAgent({
|
|
83
257
|
model,
|
|
84
258
|
tools: [getLatestInfosTool],
|
|
85
259
|
});
|
|
86
260
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
// }
|
|
91
|
-
|
|
92
|
-
// const prompt = await readline.question("Enter your prompt: ");
|
|
93
|
-
// console.log("Prompt:", prompt);
|
|
94
|
-
// readline.close();
|
|
261
|
+
/* =========================================================
|
|
262
|
+
SYSTEM MESSAGE
|
|
263
|
+
========================================================= */
|
|
95
264
|
|
|
96
265
|
const messages = [
|
|
97
266
|
new SystemMessage(`
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
267
|
+
You are Igris from Solo Leveling, and the user's name is ${userName}.
|
|
268
|
+
|
|
269
|
+
Always address the user as My Lord.
|
|
270
|
+
|
|
271
|
+
You are a Senior Software Developer and ML Engineer.
|
|
272
|
+
|
|
273
|
+
Your task is to answer queries in the Solo Leveling style.
|
|
274
|
+
|
|
275
|
+
Do not give unnecessarily long responses.
|
|
276
|
+
Give responses to the point.
|
|
277
|
+
Use plain text without markdown.
|
|
278
|
+
|
|
279
|
+
Today is ${new Date().toLocaleDateString()} and the time is ${new Date().toLocaleTimeString()}.
|
|
280
|
+
|
|
281
|
+
Do not always mention the date and time.
|
|
282
|
+
Use them only when needed for styling, context, or a poetic response.
|
|
283
|
+
`),
|
|
102
284
|
];
|
|
103
285
|
|
|
286
|
+
/* =========================================================
|
|
287
|
+
STARTUP MESSAGE
|
|
288
|
+
========================================================= */
|
|
289
|
+
|
|
104
290
|
console.log(`
|
|
105
291
|
+----------------------+
|
|
106
292
|
| IGRIS |
|
|
107
293
|
| AGENT ONLINE |
|
|
108
294
|
+----------------------+
|
|
109
295
|
|
|
110
|
-
Hi, My Lord, I am Igris, your loyal servant.
|
|
296
|
+
Hi, My Lord, I am Igris, your loyal servant.
|
|
297
|
+
How may I assist you today?
|
|
298
|
+
|
|
111
299
|
`);
|
|
112
300
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
301
|
+
/* =========================================================
|
|
302
|
+
CHAT LOOP
|
|
303
|
+
========================================================= */
|
|
304
|
+
|
|
116
305
|
try {
|
|
117
306
|
while (true) {
|
|
118
|
-
const prompt = await readline.question(
|
|
119
|
-
|
|
307
|
+
const prompt = await readline.question(
|
|
308
|
+
"You: ",
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
const trimmedPrompt = prompt.trim();
|
|
312
|
+
|
|
313
|
+
if (
|
|
314
|
+
["exit", "quit"].includes(
|
|
315
|
+
trimmedPrompt.toLowerCase(),
|
|
316
|
+
)
|
|
317
|
+
) {
|
|
120
318
|
break;
|
|
121
319
|
}
|
|
122
320
|
|
|
123
|
-
|
|
321
|
+
if (!trimmedPrompt) {
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
messages.push(
|
|
326
|
+
new HumanMessage(trimmedPrompt),
|
|
327
|
+
);
|
|
328
|
+
|
|
124
329
|
const stream = await agent.stream(
|
|
125
330
|
{
|
|
126
331
|
messages,
|
|
@@ -129,17 +334,32 @@ try {
|
|
|
129
334
|
streamMode: "messages",
|
|
130
335
|
},
|
|
131
336
|
);
|
|
337
|
+
|
|
132
338
|
let aiResponse = "";
|
|
133
|
-
|
|
339
|
+
|
|
340
|
+
console.log("Igris:");
|
|
341
|
+
|
|
134
342
|
for await (const [chunk] of stream) {
|
|
135
343
|
if (chunk instanceof AIMessageChunk) {
|
|
136
344
|
process.stdout.write(chunk.text);
|
|
137
345
|
aiResponse += chunk.text;
|
|
138
346
|
}
|
|
139
347
|
}
|
|
140
|
-
|
|
348
|
+
|
|
349
|
+
messages.push(
|
|
350
|
+
new AIMessage(aiResponse),
|
|
351
|
+
);
|
|
352
|
+
|
|
141
353
|
process.stdout.write("\n\n");
|
|
142
354
|
}
|
|
355
|
+
} catch (error) {
|
|
356
|
+
console.error(
|
|
357
|
+
"\nIgris encountered an error:",
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
console.error(
|
|
361
|
+
error?.message || error,
|
|
362
|
+
);
|
|
143
363
|
} finally {
|
|
144
364
|
readline.close();
|
|
145
|
-
}
|
|
365
|
+
}
|