jbai-cli 1.1.0 → 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 +27 -16
- package/bin/jbai-aider.js +4 -1
- package/bin/jbai-claude.js +4 -1
- package/bin/jbai-codex.js +4 -1
- package/bin/jbai-opencode.js +4 -1
- package/bin/jbai.js +163 -2
- package/lib/config.js +24 -0
- package/package.json +3 -4
- package/bin/jbai-gemini.js +0 -136
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Use AI coding tools with your JetBrains AI subscription** — no separate API keys needed.
|
|
4
4
|
|
|
5
|
-
One token, all tools: Claude Code, Codex, Aider,
|
|
5
|
+
One token, all tools: Claude Code, Codex, Aider, OpenCode.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -59,15 +59,9 @@ jbai-codex exec "explain this codebase"
|
|
|
59
59
|
### Aider
|
|
60
60
|
```bash
|
|
61
61
|
jbai-aider
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### Gemini
|
|
65
|
-
```bash
|
|
66
|
-
# Interactive chat
|
|
67
|
-
jbai-gemini
|
|
68
62
|
|
|
69
|
-
#
|
|
70
|
-
jbai-
|
|
63
|
+
# Use Gemini models with Aider
|
|
64
|
+
jbai-aider --model gemini/gemini-2.5-pro
|
|
71
65
|
```
|
|
72
66
|
|
|
73
67
|
### OpenCode
|
|
@@ -110,8 +104,8 @@ jbai-claude --model claude-opus-4-1-20250805
|
|
|
110
104
|
# Codex with GPT-5
|
|
111
105
|
jbai-codex --model gpt-5-2025-08-07
|
|
112
106
|
|
|
113
|
-
#
|
|
114
|
-
jbai-
|
|
107
|
+
# Aider with Gemini Pro
|
|
108
|
+
jbai-aider --model gemini/gemini-2.5-pro
|
|
115
109
|
```
|
|
116
110
|
|
|
117
111
|
### Available Models
|
|
@@ -135,10 +129,10 @@ jbai-gemini --model gemini-2.5-pro "Your question"
|
|
|
135
129
|
| `o3-2025-04-16` | Reasoning |
|
|
136
130
|
| `o3-mini-2025-01-31` | |
|
|
137
131
|
|
|
138
|
-
**Gemini (Google)**
|
|
132
|
+
**Gemini (Google)** - Use with Aider: `jbai-aider --model gemini/<model>`
|
|
139
133
|
| Model | Notes |
|
|
140
134
|
|-------|-------|
|
|
141
|
-
| `gemini-2.5-flash` |
|
|
135
|
+
| `gemini-2.5-flash` | Fast |
|
|
142
136
|
| `gemini-2.5-pro` | More capable |
|
|
143
137
|
| `gemini-3-pro-preview` | Preview |
|
|
144
138
|
| `gemini-3-flash-preview` | Preview |
|
|
@@ -152,12 +146,30 @@ jbai-gemini --model gemini-2.5-pro "Your question"
|
|
|
152
146
|
| `jbai token set` | Set/update token |
|
|
153
147
|
| `jbai test` | Test API connections |
|
|
154
148
|
| `jbai models` | List all models |
|
|
149
|
+
| `jbai install` | Install all AI tools |
|
|
150
|
+
| `jbai install claude` | Install specific tool |
|
|
151
|
+
| `jbai doctor` | Check tool installation status |
|
|
155
152
|
| `jbai env staging` | Use staging environment |
|
|
156
153
|
| `jbai env production` | Use production environment |
|
|
157
154
|
|
|
158
|
-
##
|
|
155
|
+
## Installing AI Tools
|
|
156
|
+
|
|
157
|
+
jbai-cli can install the underlying tools for you:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Install all tools at once
|
|
161
|
+
jbai install
|
|
162
|
+
|
|
163
|
+
# Install specific tool
|
|
164
|
+
jbai install claude
|
|
165
|
+
jbai install codex
|
|
166
|
+
jbai install aider
|
|
167
|
+
|
|
168
|
+
# Check what's installed
|
|
169
|
+
jbai doctor
|
|
170
|
+
```
|
|
159
171
|
|
|
160
|
-
|
|
172
|
+
### Manual Installation
|
|
161
173
|
|
|
162
174
|
| Tool | Install Command |
|
|
163
175
|
|------|-----------------|
|
|
@@ -165,7 +177,6 @@ Install the underlying tools you want to use:
|
|
|
165
177
|
| Codex | `npm i -g @openai/codex` |
|
|
166
178
|
| Aider | `pip install aider-chat` |
|
|
167
179
|
| OpenCode | `go install github.com/opencode-ai/opencode@latest` |
|
|
168
|
-
| Gemini | Built-in, no install needed |
|
|
169
180
|
|
|
170
181
|
## Token Management
|
|
171
182
|
|
package/bin/jbai-aider.js
CHANGED
|
@@ -49,7 +49,10 @@ const child = spawn('aider', aiderArgs, {
|
|
|
49
49
|
|
|
50
50
|
child.on('error', (err) => {
|
|
51
51
|
if (err.code === 'ENOENT') {
|
|
52
|
-
|
|
52
|
+
const tool = config.TOOLS.aider;
|
|
53
|
+
console.error(`❌ ${tool.name} not found.\n`);
|
|
54
|
+
console.error(`Install with: ${tool.install}`);
|
|
55
|
+
console.error(`Or run: jbai install aider`);
|
|
53
56
|
} else {
|
|
54
57
|
console.error(`Error: ${err.message}`);
|
|
55
58
|
}
|
package/bin/jbai-claude.js
CHANGED
|
@@ -47,7 +47,10 @@ const child = spawn('claude', finalArgs, {
|
|
|
47
47
|
|
|
48
48
|
child.on('error', (err) => {
|
|
49
49
|
if (err.code === 'ENOENT') {
|
|
50
|
-
|
|
50
|
+
const tool = config.TOOLS.claude;
|
|
51
|
+
console.error(`❌ ${tool.name} not found.\n`);
|
|
52
|
+
console.error(`Install with: ${tool.install}`);
|
|
53
|
+
console.error(`Or run: jbai install claude`);
|
|
51
54
|
} else {
|
|
52
55
|
console.error(`Error: ${err.message}`);
|
|
53
56
|
}
|
package/bin/jbai-codex.js
CHANGED
|
@@ -82,7 +82,10 @@ const child = spawn('codex', finalArgs, {
|
|
|
82
82
|
|
|
83
83
|
child.on('error', (err) => {
|
|
84
84
|
if (err.code === 'ENOENT') {
|
|
85
|
-
|
|
85
|
+
const tool = config.TOOLS.codex;
|
|
86
|
+
console.error(`❌ ${tool.name} not found.\n`);
|
|
87
|
+
console.error(`Install with: ${tool.install}`);
|
|
88
|
+
console.error(`Or run: jbai install codex`);
|
|
86
89
|
} else {
|
|
87
90
|
console.error(`Error: ${err.message}`);
|
|
88
91
|
}
|
package/bin/jbai-opencode.js
CHANGED
|
@@ -48,7 +48,10 @@ const child = spawn('opencode', finalArgs, {
|
|
|
48
48
|
|
|
49
49
|
child.on('error', (err) => {
|
|
50
50
|
if (err.code === 'ENOENT') {
|
|
51
|
-
|
|
51
|
+
const tool = config.TOOLS.opencode;
|
|
52
|
+
console.error(`❌ ${tool.name} not found.\n`);
|
|
53
|
+
console.error(`Install with: ${tool.install}`);
|
|
54
|
+
console.error(`Or run: jbai install opencode`);
|
|
52
55
|
} else {
|
|
53
56
|
console.error(`Error: ${err.message}`);
|
|
54
57
|
}
|
package/bin/jbai.js
CHANGED
|
@@ -1,10 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const { spawn } = require('child_process');
|
|
3
|
+
const { spawn, execSync } = require('child_process');
|
|
4
4
|
const readline = require('readline');
|
|
5
5
|
const https = require('https');
|
|
6
6
|
const config = require('../lib/config');
|
|
7
7
|
|
|
8
|
+
const TOOLS = {
|
|
9
|
+
claude: {
|
|
10
|
+
name: 'Claude Code',
|
|
11
|
+
command: 'claude',
|
|
12
|
+
install: 'npm install -g @anthropic-ai/claude-code',
|
|
13
|
+
check: 'claude --version'
|
|
14
|
+
},
|
|
15
|
+
codex: {
|
|
16
|
+
name: 'Codex CLI',
|
|
17
|
+
command: 'codex',
|
|
18
|
+
install: 'npm install -g @openai/codex',
|
|
19
|
+
check: 'codex --version'
|
|
20
|
+
},
|
|
21
|
+
aider: {
|
|
22
|
+
name: 'Aider',
|
|
23
|
+
command: 'aider',
|
|
24
|
+
install: 'pip install aider-chat',
|
|
25
|
+
check: 'aider --version'
|
|
26
|
+
},
|
|
27
|
+
opencode: {
|
|
28
|
+
name: 'OpenCode',
|
|
29
|
+
command: 'opencode',
|
|
30
|
+
install: 'go install github.com/opencode-ai/opencode@latest',
|
|
31
|
+
check: 'opencode --version'
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
8
35
|
const VERSION = require('../package.json').version;
|
|
9
36
|
|
|
10
37
|
const HELP = `
|
|
@@ -17,13 +44,15 @@ COMMANDS:
|
|
|
17
44
|
jbai test Test all API endpoints
|
|
18
45
|
jbai env [staging|production] Switch environment
|
|
19
46
|
jbai models List available models
|
|
47
|
+
jbai install Install all AI tools (claude, codex, aider)
|
|
48
|
+
jbai install claude Install specific tool
|
|
49
|
+
jbai doctor Check which tools are installed
|
|
20
50
|
jbai help Show this help
|
|
21
51
|
|
|
22
52
|
TOOL WRAPPERS:
|
|
23
53
|
jbai-claude Launch Claude Code with JetBrains AI
|
|
24
54
|
jbai-codex Launch Codex CLI with JetBrains AI
|
|
25
55
|
jbai-aider Launch Aider with JetBrains AI
|
|
26
|
-
jbai-gemini Launch Gemini with JetBrains AI
|
|
27
56
|
jbai-opencode Launch OpenCode with JetBrains AI
|
|
28
57
|
|
|
29
58
|
SUPER MODE:
|
|
@@ -218,6 +247,131 @@ function setEnvironment(env) {
|
|
|
218
247
|
console.log(` Token URL: ${config.ENDPOINTS[env].tokenUrl}`);
|
|
219
248
|
}
|
|
220
249
|
|
|
250
|
+
function isToolInstalled(toolKey) {
|
|
251
|
+
const tool = TOOLS[toolKey];
|
|
252
|
+
if (!tool) return false;
|
|
253
|
+
try {
|
|
254
|
+
execSync(`which ${tool.command}`, { stdio: 'ignore' });
|
|
255
|
+
return true;
|
|
256
|
+
} catch {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function doctor() {
|
|
262
|
+
console.log('Tool Status:\n');
|
|
263
|
+
|
|
264
|
+
const token = config.getToken();
|
|
265
|
+
console.log(`Token: ${token ? '✅ Set' : '❌ Not set'}`);
|
|
266
|
+
if (token) {
|
|
267
|
+
console.log(`Environment: ${config.getEnvironment()}`);
|
|
268
|
+
console.log(`Expired: ${config.isTokenExpired(token) ? '⚠️ Yes' : '✅ No'}`);
|
|
269
|
+
}
|
|
270
|
+
console.log('');
|
|
271
|
+
|
|
272
|
+
for (const [key, tool] of Object.entries(TOOLS)) {
|
|
273
|
+
const installed = isToolInstalled(key);
|
|
274
|
+
const status = installed ? '✅' : '❌';
|
|
275
|
+
console.log(`${status} ${tool.name.padEnd(12)} ${installed ? 'Installed' : 'Not installed'}`);
|
|
276
|
+
if (!installed) {
|
|
277
|
+
console.log(` Install: ${tool.install}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
console.log('\nTip: For Gemini models, use Aider: jbai-aider --model gemini/gemini-2.5-pro');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async function installTools(toolKey) {
|
|
285
|
+
const rl = readline.createInterface({
|
|
286
|
+
input: process.stdin,
|
|
287
|
+
output: process.stdout
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
const askConfirm = (question) => new Promise(resolve => {
|
|
291
|
+
rl.question(question, answer => resolve(answer.toLowerCase() === 'y' || answer === ''));
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
if (toolKey && toolKey !== 'all') {
|
|
295
|
+
// Install specific tool
|
|
296
|
+
const tool = TOOLS[toolKey];
|
|
297
|
+
if (!tool) {
|
|
298
|
+
console.log(`Unknown tool: ${toolKey}`);
|
|
299
|
+
console.log(`Available: ${Object.keys(TOOLS).join(', ')}`);
|
|
300
|
+
rl.close();
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (isToolInstalled(toolKey)) {
|
|
305
|
+
console.log(`✅ ${tool.name} is already installed`);
|
|
306
|
+
rl.close();
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
console.log(`Installing ${tool.name}...`);
|
|
311
|
+
console.log(`Running: ${tool.install}\n`);
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
execSync(tool.install, { stdio: 'inherit' });
|
|
315
|
+
console.log(`\n✅ ${tool.name} installed successfully`);
|
|
316
|
+
} catch (e) {
|
|
317
|
+
console.log(`\n❌ Failed to install ${tool.name}`);
|
|
318
|
+
}
|
|
319
|
+
rl.close();
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Install all tools
|
|
324
|
+
console.log('This will install the following tools:\n');
|
|
325
|
+
|
|
326
|
+
const toInstall = [];
|
|
327
|
+
for (const [key, tool] of Object.entries(TOOLS)) {
|
|
328
|
+
const installed = isToolInstalled(key);
|
|
329
|
+
if (installed) {
|
|
330
|
+
console.log(`✅ ${tool.name} - already installed`);
|
|
331
|
+
} else {
|
|
332
|
+
console.log(`📦 ${tool.name} - will install`);
|
|
333
|
+
console.log(` ${tool.install}`);
|
|
334
|
+
toInstall.push({ key, tool });
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (toInstall.length === 0) {
|
|
339
|
+
console.log('\n✅ All tools are already installed!');
|
|
340
|
+
rl.close();
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
console.log('');
|
|
345
|
+
const confirm = await askConfirm(`Install ${toInstall.length} tool(s)? [Y/n] `);
|
|
346
|
+
|
|
347
|
+
if (!confirm) {
|
|
348
|
+
console.log('Cancelled');
|
|
349
|
+
rl.close();
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
for (const { key, tool } of toInstall) {
|
|
354
|
+
console.log(`\n📦 Installing ${tool.name}...`);
|
|
355
|
+
console.log(`Running: ${tool.install}\n`);
|
|
356
|
+
|
|
357
|
+
try {
|
|
358
|
+
execSync(tool.install, { stdio: 'inherit' });
|
|
359
|
+
console.log(`✅ ${tool.name} installed`);
|
|
360
|
+
} catch (e) {
|
|
361
|
+
console.log(`❌ Failed to install ${tool.name}`);
|
|
362
|
+
const skip = await askConfirm('Continue with other tools? [Y/n] ');
|
|
363
|
+
if (!skip) {
|
|
364
|
+
rl.close();
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
rl.close();
|
|
371
|
+
console.log('\n✅ Installation complete!');
|
|
372
|
+
console.log('Run: jbai doctor to verify');
|
|
373
|
+
}
|
|
374
|
+
|
|
221
375
|
// Main
|
|
222
376
|
const [,, command, ...args] = process.argv;
|
|
223
377
|
|
|
@@ -238,6 +392,13 @@ switch (command) {
|
|
|
238
392
|
case 'env':
|
|
239
393
|
setEnvironment(args[0]);
|
|
240
394
|
break;
|
|
395
|
+
case 'install':
|
|
396
|
+
installTools(args[0]);
|
|
397
|
+
break;
|
|
398
|
+
case 'doctor':
|
|
399
|
+
case 'status':
|
|
400
|
+
doctor();
|
|
401
|
+
break;
|
|
241
402
|
case 'help':
|
|
242
403
|
case '--help':
|
|
243
404
|
case '-h':
|
package/lib/config.js
CHANGED
|
@@ -122,12 +122,36 @@ function isTokenExpired(token) {
|
|
|
122
122
|
return expiry < new Date();
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
const TOOLS = {
|
|
126
|
+
claude: {
|
|
127
|
+
name: 'Claude Code',
|
|
128
|
+
command: 'claude',
|
|
129
|
+
install: 'npm install -g @anthropic-ai/claude-code'
|
|
130
|
+
},
|
|
131
|
+
codex: {
|
|
132
|
+
name: 'Codex CLI',
|
|
133
|
+
command: 'codex',
|
|
134
|
+
install: 'npm install -g @openai/codex'
|
|
135
|
+
},
|
|
136
|
+
aider: {
|
|
137
|
+
name: 'Aider',
|
|
138
|
+
command: 'aider',
|
|
139
|
+
install: 'pip install aider-chat'
|
|
140
|
+
},
|
|
141
|
+
opencode: {
|
|
142
|
+
name: 'OpenCode',
|
|
143
|
+
command: 'opencode',
|
|
144
|
+
install: 'go install github.com/opencode-ai/opencode@latest'
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
125
148
|
module.exports = {
|
|
126
149
|
CONFIG_DIR,
|
|
127
150
|
TOKEN_FILE,
|
|
128
151
|
CONFIG_FILE,
|
|
129
152
|
ENDPOINTS,
|
|
130
153
|
MODELS,
|
|
154
|
+
TOOLS,
|
|
131
155
|
ensureConfigDir,
|
|
132
156
|
getToken,
|
|
133
157
|
setToken,
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jbai-cli",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "CLI wrappers to use AI coding tools (Claude Code, Codex, Aider,
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "CLI wrappers to use AI coding tools (Claude Code, Codex, Aider, OpenCode) with JetBrains AI Platform",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jetbrains",
|
|
7
7
|
"ai",
|
|
8
8
|
"claude",
|
|
9
9
|
"codex",
|
|
10
10
|
"aider",
|
|
11
|
-
"
|
|
11
|
+
"opencode",
|
|
12
12
|
"cli",
|
|
13
13
|
"openai",
|
|
14
14
|
"anthropic"
|
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
"jbai-claude": "./bin/jbai-claude.js",
|
|
29
29
|
"jbai-codex": "./bin/jbai-codex.js",
|
|
30
30
|
"jbai-aider": "./bin/jbai-aider.js",
|
|
31
|
-
"jbai-gemini": "./bin/jbai-gemini.js",
|
|
32
31
|
"jbai-opencode": "./bin/jbai-opencode.js"
|
|
33
32
|
},
|
|
34
33
|
"files": [
|
package/bin/jbai-gemini.js
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const https = require('https');
|
|
4
|
-
const readline = require('readline');
|
|
5
|
-
const config = require('../lib/config');
|
|
6
|
-
|
|
7
|
-
const token = config.getToken();
|
|
8
|
-
if (!token) {
|
|
9
|
-
console.error('❌ No token found. Run: jbai token set');
|
|
10
|
-
process.exit(1);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if (config.isTokenExpired(token)) {
|
|
14
|
-
console.error('⚠️ Token expired. Run: jbai token refresh');
|
|
15
|
-
process.exit(1);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const endpoints = config.getEndpoints();
|
|
19
|
-
const args = process.argv.slice(2);
|
|
20
|
-
|
|
21
|
-
// Get model from args or use default
|
|
22
|
-
let model = config.MODELS.gemini.default;
|
|
23
|
-
const modelIdx = args.indexOf('--model');
|
|
24
|
-
if (modelIdx !== -1 && args[modelIdx + 1]) {
|
|
25
|
-
model = args[modelIdx + 1];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// If prompt provided as argument, run one-shot
|
|
29
|
-
const prompt = args.filter((a, i) =>
|
|
30
|
-
a !== '--model' && (modelIdx === -1 || i !== modelIdx + 1)
|
|
31
|
-
).join(' ');
|
|
32
|
-
|
|
33
|
-
if (prompt) {
|
|
34
|
-
runPrompt(prompt, model);
|
|
35
|
-
} else {
|
|
36
|
-
runInteractive(model);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async function runPrompt(prompt, model) {
|
|
40
|
-
const url = `${endpoints.google}/v1/projects/default/locations/default/publishers/google/models/${model}:generateContent`;
|
|
41
|
-
|
|
42
|
-
try {
|
|
43
|
-
const result = await httpPost(url, {
|
|
44
|
-
contents: [{ role: 'user', parts: [{ text: prompt }] }]
|
|
45
|
-
}, { 'Grazie-Authenticate-JWT': token });
|
|
46
|
-
|
|
47
|
-
if (result.candidates && result.candidates[0]) {
|
|
48
|
-
console.log(result.candidates[0].content.parts[0].text);
|
|
49
|
-
} else if (result.error) {
|
|
50
|
-
console.error(`Error: ${result.error.message}`);
|
|
51
|
-
}
|
|
52
|
-
} catch (e) {
|
|
53
|
-
console.error(`Error: ${e.message}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async function runInteractive(model) {
|
|
58
|
-
console.log(`Gemini Interactive (${model})`);
|
|
59
|
-
console.log('Type your message, press Enter to send. Ctrl+C to exit.\n');
|
|
60
|
-
|
|
61
|
-
const rl = readline.createInterface({
|
|
62
|
-
input: process.stdin,
|
|
63
|
-
output: process.stdout
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
const history = [];
|
|
67
|
-
|
|
68
|
-
const askQuestion = () => {
|
|
69
|
-
rl.question('You: ', async (input) => {
|
|
70
|
-
if (!input.trim()) {
|
|
71
|
-
askQuestion();
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
history.push({ role: 'user', parts: [{ text: input }] });
|
|
76
|
-
|
|
77
|
-
const url = `${endpoints.google}/v1/projects/default/locations/default/publishers/google/models/${model}:generateContent`;
|
|
78
|
-
|
|
79
|
-
try {
|
|
80
|
-
const result = await httpPost(url, { contents: history }, { 'Grazie-Authenticate-JWT': token });
|
|
81
|
-
|
|
82
|
-
if (result.candidates && result.candidates[0]) {
|
|
83
|
-
const response = result.candidates[0].content.parts[0].text;
|
|
84
|
-
history.push({ role: 'model', parts: [{ text: response }] });
|
|
85
|
-
console.log(`\nGemini: ${response}\n`);
|
|
86
|
-
} else if (result.error) {
|
|
87
|
-
console.error(`Error: ${result.error.message}\n`);
|
|
88
|
-
}
|
|
89
|
-
} catch (e) {
|
|
90
|
-
console.error(`Error: ${e.message}\n`);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
askQuestion();
|
|
94
|
-
});
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
rl.on('close', () => {
|
|
98
|
-
console.log('\nGoodbye!');
|
|
99
|
-
process.exit(0);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
askQuestion();
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function httpPost(url, body, headers) {
|
|
106
|
-
return new Promise((resolve, reject) => {
|
|
107
|
-
const urlObj = new URL(url);
|
|
108
|
-
const data = JSON.stringify(body);
|
|
109
|
-
|
|
110
|
-
const req = https.request({
|
|
111
|
-
hostname: urlObj.hostname,
|
|
112
|
-
port: 443,
|
|
113
|
-
path: urlObj.pathname,
|
|
114
|
-
method: 'POST',
|
|
115
|
-
headers: {
|
|
116
|
-
'Content-Type': 'application/json',
|
|
117
|
-
'Content-Length': Buffer.byteLength(data),
|
|
118
|
-
...headers
|
|
119
|
-
}
|
|
120
|
-
}, (res) => {
|
|
121
|
-
let body = '';
|
|
122
|
-
res.on('data', chunk => body += chunk);
|
|
123
|
-
res.on('end', () => {
|
|
124
|
-
try {
|
|
125
|
-
resolve(JSON.parse(body));
|
|
126
|
-
} catch {
|
|
127
|
-
reject(new Error('Invalid response'));
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
req.on('error', reject);
|
|
133
|
-
req.write(data);
|
|
134
|
-
req.end();
|
|
135
|
-
});
|
|
136
|
-
}
|