@dubeyvishal/orbital-cli 1.6.14 → 1.6.16
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 +3 -3
- package/package.json +2 -4
- package/server/src/cli/ai/googleService.js +30 -80
- package/server/src/cli/chat/chat-with-ai-agent.js +20 -40
- package/server/src/cli/chat/chat-with-ai-tools.js +46 -108
- package/server/src/cli/chat/chat-with-ai.js +197 -232
- package/server/src/cli/commands/ai/wakeUp.js +78 -139
- package/server/src/cli/commands/auth/login.js +7 -1
- package/server/src/cli/commands/config/setkey.js +6 -57
- package/server/src/cli/main.js +1 -1
- package/server/src/config/googleConfig.js +1 -1
- package/server/src/config/toolConfig.js +44 -25
- package/server/src/controllers/aiController.js +6 -10
- package/server/src/lib/credentialStore.js +14 -47
- package/server/src/lib/orbitalConfig.js +38 -144
- package/server/src/service/aiService.js +2 -2
- package/server/src/config/aiConfig.js +0 -159
|
@@ -1,98 +1,85 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import boxen from "boxen";
|
|
3
|
-
import {
|
|
3
|
+
import {text , isCancel , cancel , intro , outro }from "@clack/prompts";
|
|
4
4
|
import yoctoSpinner from "yocto-spinner";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
5
|
+
import {marked} from "marked";
|
|
6
|
+
import {markedTerminal} from "marked-terminal";
|
|
7
|
+
import {getStoredToken} from "../../lib/token.js";
|
|
8
8
|
import { apiRequestSafe } from "../utils/apiClient.js";
|
|
9
9
|
import { AIService } from "../ai/googleService.js";
|
|
10
|
-
import {
|
|
11
|
-
import { parseModelChoice } from "../../config/aiConfig.js";
|
|
12
|
-
|
|
10
|
+
import { requireGeminiApiKey } from "../../lib/orbitalConfig.js";
|
|
13
11
|
|
|
14
12
|
marked.use(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
)
|
|
13
|
+
markedTerminal({
|
|
14
|
+
code : chalk.cyan ,
|
|
15
|
+
blockquote : chalk.gray.italic ,
|
|
16
|
+
heading : chalk.green.bold ,
|
|
17
|
+
firstHeading: chalk.magenta.underline.bold ,
|
|
18
|
+
hr : chalk.reset ,
|
|
19
|
+
listitem : chalk.reset ,
|
|
20
|
+
list : chalk.reset ,
|
|
21
|
+
paragraph : chalk.reset ,
|
|
22
|
+
strong : chalk.bold ,
|
|
23
|
+
em : chalk.italic ,
|
|
24
|
+
codespan : chalk.yellow.bgBlack ,
|
|
25
|
+
del : chalk.dim.gray.strikethrough ,
|
|
26
|
+
link : chalk.blue.underline ,
|
|
27
|
+
href : chalk.blue.underline
|
|
28
|
+
})
|
|
29
|
+
)
|
|
32
30
|
|
|
33
|
-
const getUserFromToken = async
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
const getUserFromToken = async()=>{
|
|
32
|
+
const token = await getStoredToken()
|
|
33
|
+
if(!token?.access_token){
|
|
34
|
+
throw new Error("Not authenticated. Please run 'orbital login' first.");
|
|
35
|
+
}
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
37
|
+
const spinner = yoctoSpinner({text: "Authenticating..."}).start();
|
|
38
|
+
try {
|
|
39
|
+
const result = await apiRequestSafe("/api/cli/me");
|
|
40
|
+
const user = result?.user;
|
|
41
|
+
if(!user){
|
|
42
|
+
spinner.error("User not found");
|
|
43
|
+
throw new Error("User not found. Please login again");
|
|
44
|
+
}
|
|
45
|
+
spinner.success(`Welcome back , ${user.name}!`);
|
|
46
|
+
return user;
|
|
47
|
+
} finally {
|
|
48
|
+
spinner.stop();
|
|
46
49
|
}
|
|
47
|
-
|
|
48
|
-
return user;
|
|
49
|
-
} finally {
|
|
50
|
-
spinner.stop();
|
|
51
|
-
}
|
|
52
|
-
};
|
|
50
|
+
}
|
|
53
51
|
|
|
54
|
-
const initConversation = async
|
|
55
|
-
|
|
56
|
-
conversationId = null,
|
|
57
|
-
mode = "chat",
|
|
58
|
-
modelDisplayName = null
|
|
59
|
-
) => {
|
|
60
|
-
const spinner = yoctoSpinner({ text: "Loading conversation..." }).start();
|
|
52
|
+
const initConversation = async(userId , conversationId = null , mode = "chat")=>{
|
|
53
|
+
const spinner = yoctoSpinner({text : "Loading conservation ..."}).start();
|
|
61
54
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
55
|
+
const result = await apiRequestSafe("/api/cli/conversations/init", {
|
|
56
|
+
method: "POST",
|
|
57
|
+
body: { conversationId, mode },
|
|
58
|
+
});
|
|
59
|
+
const conversation = result?.conversation;
|
|
60
|
+
const messages = result?.messages || [];
|
|
61
|
+
spinner.success("Conversation Loaded");
|
|
69
62
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
63
|
+
const conversationInfo = boxen(
|
|
64
|
+
`${chalk.bold("Conversation")} : ${conversation.title}\n ${chalk.gray("ID: " + conversation.id)} \n ${chalk.gray("Mode: " + conversation.mode)}`,
|
|
65
|
+
{
|
|
66
|
+
padding : 1 ,
|
|
67
|
+
margin : {top: 1 , bottom : 1} ,
|
|
68
|
+
borderStyle : "round" ,
|
|
69
|
+
borderColor : "cyan" ,
|
|
70
|
+
title : "Chat Settion",
|
|
71
|
+
titleAlignment : "center"
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
console.log(conversationInfo);
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
)}\n ${chalk.gray("Mode: " + conversation.mode)}${modelLine}`,
|
|
78
|
-
{
|
|
79
|
-
padding: 1,
|
|
80
|
-
margin: { top: 1, bottom: 1 },
|
|
81
|
-
borderStyle: "round",
|
|
82
|
-
borderColor: "cyan",
|
|
83
|
-
title: "Chat Session",
|
|
84
|
-
titleAlignment: "center",
|
|
76
|
+
if(messages.length > 0){
|
|
77
|
+
console.log(chalk.yellow("Previous Messsages: \n"));
|
|
78
|
+
displayMessages(messages);
|
|
85
79
|
}
|
|
86
|
-
);
|
|
87
|
-
console.log(conversationInfo);
|
|
88
80
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
displayMessages(messages);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return conversation;
|
|
95
|
-
};
|
|
81
|
+
return conversation ;
|
|
82
|
+
}
|
|
96
83
|
|
|
97
84
|
const displayMessages = (messages) => {
|
|
98
85
|
messages.forEach((msg) => {
|
|
@@ -121,175 +108,153 @@ const displayMessages = (messages) => {
|
|
|
121
108
|
});
|
|
122
109
|
};
|
|
123
110
|
|
|
124
|
-
const saveMessage = async
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
111
|
+
const saveMessage = async(conversationId , role , content) =>{
|
|
112
|
+
return await apiRequestSafe("/api/cli/messages", {
|
|
113
|
+
method: "POST",
|
|
114
|
+
body: { conversationId, role, content },
|
|
115
|
+
});
|
|
116
|
+
}
|
|
130
117
|
|
|
131
|
-
const getAIResponse
|
|
132
|
-
|
|
133
|
-
|
|
118
|
+
const getAIResponse = async(conversationId)=>{
|
|
119
|
+
const spinner = yoctoSpinner({
|
|
120
|
+
text : "AI is thinking...",
|
|
121
|
+
color: "cyan"
|
|
122
|
+
}).start();
|
|
134
123
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
124
|
+
let fullResponse = "";
|
|
125
|
+
try{
|
|
126
|
+
const messageResult = await apiRequestSafe(
|
|
127
|
+
`/api/cli/messages?conversationId=${encodeURIComponent(conversationId)}`,
|
|
128
|
+
{ method: "GET" }
|
|
129
|
+
);
|
|
139
130
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const messageResult = await apiRequestSafe(
|
|
143
|
-
`/api/cli/messages?conversationId=${encodeURIComponent(conversationId)}`,
|
|
144
|
-
{ method: "GET" }
|
|
145
|
-
);
|
|
131
|
+
const messages = Array.isArray(messageResult?.messages) ? messageResult.messages : [];
|
|
132
|
+
const aiMessages = messages.map((m) => ({ role: m.role, content: m.content }));
|
|
146
133
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const aiMessages = messages.map((m) => ({
|
|
151
|
-
role: m.role,
|
|
152
|
-
content: m.content,
|
|
153
|
-
}));
|
|
134
|
+
await requireGeminiApiKey();
|
|
135
|
+
const aiService = new AIService();
|
|
136
|
+
const result = await aiService.sendMessage(aiMessages);
|
|
154
137
|
|
|
155
|
-
|
|
138
|
+
spinner.stop();
|
|
139
|
+
console.log("\n");
|
|
140
|
+
const header = chalk.green.bold("Assistent: ");
|
|
141
|
+
console.log(header);
|
|
142
|
+
console.log(chalk.gray("-".repeat(60)));
|
|
156
143
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
144
|
+
fullResponse = result?.content || "";
|
|
145
|
+
console.log("\n");
|
|
146
|
+
const renderMarkdown = marked.parse(fullResponse);
|
|
147
|
+
console.log(renderMarkdown);
|
|
148
|
+
console.log(chalk.gray("-".repeat(60)));
|
|
149
|
+
console.log("\n");
|
|
162
150
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
151
|
+
return fullResponse ;
|
|
152
|
+
}
|
|
153
|
+
catch(error){
|
|
154
|
+
spinner.error("Failed to get AI response");
|
|
155
|
+
throw error ;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
169
158
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
159
|
+
const updateConversationTitle = async(conversationId , userInput , messageCount)=>{
|
|
160
|
+
if(messageCount ===1){
|
|
161
|
+
const title = userInput.slice(0,50) + (userInput.length > 50 ? "..." : "");
|
|
162
|
+
await apiRequestSafe(`/api/cli/conversations/${conversationId}/title`, {
|
|
163
|
+
method: "PATCH",
|
|
164
|
+
body: { title },
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
176
168
|
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
};
|
|
169
|
+
const chatLoop = async(conversation)=>{
|
|
170
|
+
const helpBox = boxen(
|
|
171
|
+
`${chalk.gray(`* Type your message and press Enter`)}\n ${chalk.gray(`* Markdown formatting is supported in response`)}
|
|
172
|
+
\n${chalk.gray(`*Type "exit" to end conversation`)}\n ${chalk.gray(`*Please ctrl + C to quit anytime`)}`,
|
|
173
|
+
{
|
|
174
|
+
padding : 1 ,
|
|
175
|
+
margin : {bottom : 1},
|
|
176
|
+
borderStyle : "round" ,
|
|
177
|
+
borderColor : "gray" ,
|
|
178
|
+
dimBorder : true
|
|
179
|
+
}
|
|
180
|
+
);
|
|
181
|
+
console.log(helpBox);
|
|
191
182
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
borderStyle: "round",
|
|
203
|
-
borderColor: "gray",
|
|
204
|
-
dimBorder: true,
|
|
205
|
-
}
|
|
206
|
-
);
|
|
207
|
-
console.log(helpBox);
|
|
183
|
+
while(true){
|
|
184
|
+
const userInput = await text({
|
|
185
|
+
message: chalk.blue("Your message"),
|
|
186
|
+
placeholder : "Type your message...",
|
|
187
|
+
validate(value){
|
|
188
|
+
if(!value || value.trim().length ===0){
|
|
189
|
+
return "Message cannot be empty";
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
});
|
|
208
193
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
194
|
+
if(isCancel(userInput)){
|
|
195
|
+
const exitBox = boxen(chalk.yellow("Chat session ended. GoodBye! "),{
|
|
196
|
+
padding : 1 ,
|
|
197
|
+
margin : 1,
|
|
198
|
+
borderStyle : "round" ,
|
|
199
|
+
borderColor : "yellow" ,
|
|
200
|
+
});
|
|
201
|
+
console.log(exitBox);
|
|
202
|
+
process.exit(0);
|
|
216
203
|
}
|
|
217
|
-
|
|
218
|
-
|
|
204
|
+
if(userInput.trim().toLowerCase() === "exit"){
|
|
205
|
+
const exitBox = boxen(chalk.yellow("Chat session ended. GoodBye! "),{
|
|
206
|
+
padding : 1 ,
|
|
207
|
+
margin : 1,
|
|
208
|
+
borderStyle : "round" ,
|
|
209
|
+
borderColor : "yellow" ,
|
|
210
|
+
});
|
|
211
|
+
console.log(exitBox);
|
|
212
|
+
break ;
|
|
213
|
+
}
|
|
214
|
+
await saveMessage(conversation.id , "user" , userInput);
|
|
215
|
+
const messageResult = await apiRequestSafe(
|
|
216
|
+
`/api/cli/messages?conversationId=${encodeURIComponent(conversation.id)}`,
|
|
217
|
+
{ method: "GET" }
|
|
218
|
+
);
|
|
219
219
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
padding: 1,
|
|
223
|
-
margin: 1,
|
|
224
|
-
borderStyle: "round",
|
|
225
|
-
borderColor: "yellow",
|
|
226
|
-
});
|
|
227
|
-
console.log(exitBox);
|
|
228
|
-
process.exit(0);
|
|
229
|
-
}
|
|
230
|
-
if (userInput.trim().toLowerCase() === "exit") {
|
|
231
|
-
const exitBox = boxen(chalk.yellow("Chat session ended. Goodbye!"), {
|
|
232
|
-
padding: 1,
|
|
233
|
-
margin: 1,
|
|
234
|
-
borderStyle: "round",
|
|
235
|
-
borderColor: "yellow",
|
|
236
|
-
});
|
|
237
|
-
console.log(exitBox);
|
|
238
|
-
break;
|
|
239
|
-
}
|
|
240
|
-
await saveMessage(conversation.id, "user", userInput);
|
|
241
|
-
const messageResult = await apiRequestSafe(
|
|
242
|
-
`/api/cli/messages?conversationId=${encodeURIComponent(conversation.id)}`,
|
|
243
|
-
{ method: "GET" }
|
|
244
|
-
);
|
|
220
|
+
const aiResponse = await getAIResponse(conversation.id);
|
|
221
|
+
await saveMessage(conversation.id , "assistant" , aiResponse);
|
|
245
222
|
|
|
246
|
-
|
|
247
|
-
|
|
223
|
+
await updateConversationTitle(
|
|
224
|
+
conversation.id ,
|
|
225
|
+
userInput ,
|
|
226
|
+
messageResult?.messages?.length || 0
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
}
|
|
248
230
|
|
|
249
|
-
await updateConversationTitle(
|
|
250
|
-
conversation.id,
|
|
251
|
-
userInput,
|
|
252
|
-
messageResult?.messages?.length || 0
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
231
|
|
|
257
|
-
export const startChat = async (
|
|
258
|
-
mode = "chat",
|
|
259
|
-
conversationId = null,
|
|
260
|
-
modelConfig = null
|
|
261
|
-
) => {
|
|
262
|
-
try {
|
|
263
|
-
intro(
|
|
264
|
-
boxen(chalk.bold.cyan("Orbital AI Chat"), {
|
|
265
|
-
padding: 1,
|
|
266
|
-
borderStyle: "double",
|
|
267
|
-
borderColor: "cyan",
|
|
268
|
-
})
|
|
269
|
-
);
|
|
270
232
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
233
|
+
export const startChat = async(mode="chat" , conversationId = null)=>{
|
|
234
|
+
try{
|
|
235
|
+
intro(
|
|
236
|
+
boxen(chalk.bold.cyan("Orbital AI Chat") , {
|
|
237
|
+
padding: 1 ,
|
|
238
|
+
borderStyle : "double",
|
|
239
|
+
borderColor: "cyan"
|
|
240
|
+
})
|
|
241
|
+
)
|
|
274
242
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
conversationId,
|
|
279
|
-
mode,
|
|
280
|
-
aiService.getDisplayName()
|
|
281
|
-
);
|
|
282
|
-
await chatLoop(conversation, modelConfig);
|
|
243
|
+
const user = await getUserFromToken()
|
|
244
|
+
const conversation = await initConversation(user.id , conversationId , mode);
|
|
245
|
+
await chatLoop(conversation)
|
|
283
246
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
247
|
+
outro(chalk.green("Thanks for chatting"))
|
|
248
|
+
}
|
|
249
|
+
catch(error){
|
|
250
|
+
const errorBox = boxen(chalk.red(`Error: ${error.message}`),{
|
|
251
|
+
padding : 1 ,
|
|
252
|
+
margin : 1 ,
|
|
253
|
+
borderStyle : "round",
|
|
254
|
+
borderColor : "red",
|
|
255
|
+
|
|
256
|
+
});
|
|
257
|
+
console.log(errorBox);
|
|
258
|
+
process.exit(1);
|
|
259
|
+
}
|
|
260
|
+
}
|