@dubeyvishal/orbital-cli 1.6.13 → 1.6.14
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/package.json +4 -2
- package/server/src/cli/ai/googleService.js +80 -30
- package/server/src/cli/chat/chat-with-ai-agent.js +40 -20
- package/server/src/cli/chat/chat-with-ai-tools.js +108 -46
- package/server/src/cli/chat/chat-with-ai.js +232 -197
- package/server/src/cli/commands/ai/wakeUp.js +139 -78
- package/server/src/cli/commands/auth/login.js +1 -7
- package/server/src/cli/commands/config/setkey.js +57 -6
- package/server/src/cli/main.js +4 -1
- package/server/src/config/aiConfig.js +159 -0
- package/server/src/config/googleConfig.js +1 -1
- package/server/src/config/toolConfig.js +25 -44
- package/server/src/controllers/aiController.js +10 -6
- package/server/src/lib/credentialStore.js +47 -14
- package/server/src/lib/orbitalConfig.js +144 -38
- package/server/src/service/aiService.js +5 -5
|
@@ -1,84 +1,145 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import {Command} from "commander";
|
|
3
|
-
import yoctoSpinner
|
|
4
|
-
import {getStoredToken} from "../../../lib/token.js"
|
|
5
|
-
import {select} from "@clack/prompts";
|
|
6
|
-
import {startChat} from "../../../cli/chat/chat-with-ai.js";
|
|
7
|
-
import {startToolChat} from "../../../cli/chat/chat-with-ai-tools.js";
|
|
8
|
-
import {startAgentChat} from "../../../cli/chat/chat-with-ai-agent.js";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import yoctoSpinner from "yocto-spinner";
|
|
4
|
+
import { getStoredToken } from "../../../lib/token.js";
|
|
5
|
+
import { select, password, isCancel, cancel } from "@clack/prompts";
|
|
6
|
+
import { startChat } from "../../../cli/chat/chat-with-ai.js";
|
|
7
|
+
import { startToolChat } from "../../../cli/chat/chat-with-ai-tools.js";
|
|
8
|
+
import { startAgentChat } from "../../../cli/chat/chat-with-ai-agent.js";
|
|
9
9
|
import { apiRequestSafe } from "../../utils/apiClient.js";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
getApiKey,
|
|
12
|
+
setApiKey,
|
|
13
|
+
getSelectedModel,
|
|
14
|
+
saveSelectedModel,
|
|
15
|
+
} from "../../../lib/orbitalConfig.js";
|
|
16
|
+
import {
|
|
17
|
+
AI_PROVIDERS,
|
|
18
|
+
getModelSelectOptions,
|
|
19
|
+
parseModelChoice,
|
|
20
|
+
getModelDisplayName,
|
|
21
|
+
} from "../../../config/aiConfig.js";
|
|
11
22
|
|
|
23
|
+
const wakeUpAction = async () => {
|
|
24
|
+
const token = await getStoredToken();
|
|
25
|
+
if (!token?.access_token) {
|
|
26
|
+
console.log(chalk.red("Not Authenticated. Please run 'orbital login' first."));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
12
29
|
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
30
|
+
const spinner = yoctoSpinner({ text: "Fetching user information..." });
|
|
31
|
+
spinner.start();
|
|
32
|
+
|
|
33
|
+
let user;
|
|
34
|
+
try {
|
|
35
|
+
const result = await apiRequestSafe("/api/cli/me");
|
|
36
|
+
user = result?.user;
|
|
37
|
+
} finally {
|
|
38
|
+
spinner.stop();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!user) {
|
|
42
|
+
console.log(chalk.red("User not found. Please log in again with 'orbital login'."));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log(chalk.green(`Welcome back, ${user.name}! \n`));
|
|
47
|
+
|
|
48
|
+
// 1. Ask user to select the AI model FIRST
|
|
49
|
+
const savedModel = await getSelectedModel();
|
|
50
|
+
const modelOptions = getModelSelectOptions();
|
|
51
|
+
const defaultModelValue = `${savedModel.provider}:${savedModel.model}`;
|
|
52
|
+
|
|
53
|
+
const selectedModelChoice = await select({
|
|
54
|
+
message: "Select an AI Model:",
|
|
55
|
+
options: modelOptions,
|
|
56
|
+
initialValue: modelOptions.some((o) => o.value === defaultModelValue)
|
|
57
|
+
? defaultModelValue
|
|
58
|
+
: undefined,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (isCancel(selectedModelChoice)) {
|
|
62
|
+
cancel("Model selection cancelled.");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const { provider, model } = parseModelChoice(selectedModelChoice);
|
|
67
|
+
await saveSelectedModel({ provider, model });
|
|
68
|
+
|
|
69
|
+
// 2. Ensure API key is configured for the chosen model/provider
|
|
70
|
+
let apiKey = await getApiKey(provider);
|
|
71
|
+
if (!apiKey) {
|
|
72
|
+
const provInfo = AI_PROVIDERS[provider];
|
|
73
|
+
console.log(
|
|
74
|
+
chalk.yellow(
|
|
75
|
+
`\n${provInfo?.name || provider} API key is required. (Obtain one at: ${provInfo?.docsUrl || "provider portal"})`
|
|
76
|
+
)
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const enteredKey = await password({
|
|
80
|
+
message: `Enter your ${provInfo?.name || provider} API key:`,
|
|
81
|
+
validate(value) {
|
|
82
|
+
if (!value || !value.trim()) return "API key cannot be empty";
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
if (isCancel(enteredKey)) {
|
|
87
|
+
cancel("Operation cancelled.");
|
|
88
|
+
return;
|
|
19
89
|
}
|
|
20
90
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
break ;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export const wakeUp = new Command("wakeup").
|
|
81
|
-
description("Wake up the AI").
|
|
82
|
-
alias("wake-up").
|
|
83
|
-
alias("wakup").
|
|
84
|
-
action(wakeUpAction)
|
|
91
|
+
await setApiKey(provider, enteredKey);
|
|
92
|
+
console.log(chalk.green(`✔ ${provInfo?.name || provider} API key saved securely.\n`));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log(
|
|
96
|
+
chalk.cyan(`Active AI Model: ${chalk.bold(getModelDisplayName(provider, model))}\n`)
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// 3. Mode selection
|
|
100
|
+
const choice = await select({
|
|
101
|
+
message: "Select an Option",
|
|
102
|
+
options: [
|
|
103
|
+
{
|
|
104
|
+
value: "chat",
|
|
105
|
+
label: "Chat",
|
|
106
|
+
hint: "Simple chat with AI",
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
value: "tool",
|
|
110
|
+
label: "Tool Calling",
|
|
111
|
+
hint: "Chat with tools and code execution",
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
value: "agent",
|
|
115
|
+
label: "Agentic Mode",
|
|
116
|
+
hint: "Fullstack application generation agent",
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
if (isCancel(choice)) {
|
|
122
|
+
cancel("Operation cancelled.");
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const modelConfig = { provider, model };
|
|
127
|
+
|
|
128
|
+
switch (choice) {
|
|
129
|
+
case "chat":
|
|
130
|
+
await startChat("chat", null, modelConfig);
|
|
131
|
+
break;
|
|
132
|
+
case "tool":
|
|
133
|
+
await startToolChat(modelConfig);
|
|
134
|
+
break;
|
|
135
|
+
case "agent":
|
|
136
|
+
await startAgentChat(modelConfig);
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export const wakeUp = new Command("wakeup")
|
|
142
|
+
.description("Wake up the AI")
|
|
143
|
+
.alias("wake-up")
|
|
144
|
+
.alias("wakup")
|
|
145
|
+
.action(wakeUpAction);
|
|
@@ -11,7 +11,6 @@ import { fileURLToPath } from "url";
|
|
|
11
11
|
import { getStoredToken, isTokenExpired, storeToken ,TOKEN_FILE } from "../../../lib/token.js";
|
|
12
12
|
import { API_BASE } from "../../../config/api.js";
|
|
13
13
|
import { apiRequestSafe } from "../../utils/apiClient.js";
|
|
14
|
-
import { requireGeminiApiKey } from "../../../lib/orbitalConfig.js";
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -93,12 +92,7 @@ const resolveClientId = async (cliClientId) => {
|
|
|
93
92
|
|
|
94
93
|
|
|
95
94
|
export const loginAction = async (cmdOptions) => {
|
|
96
|
-
|
|
97
|
-
await requireGeminiApiKey();
|
|
98
|
-
} catch {
|
|
99
|
-
console.log(chalk.red("Gemini API key not set. Run: orbital set-key <API_KEY>"));
|
|
100
|
-
process.exit(1);
|
|
101
|
-
}
|
|
95
|
+
|
|
102
96
|
|
|
103
97
|
const schema = z.object({
|
|
104
98
|
serverUrl: z.string().optional(),
|
|
@@ -1,12 +1,58 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import chalk from "chalk";
|
|
3
|
-
import {
|
|
3
|
+
import { select, password, isCancel, cancel } from "@clack/prompts";
|
|
4
|
+
import { setApiKey, normalizeProviderName } from "../../../lib/orbitalConfig.js";
|
|
4
5
|
import { getCredentialServiceName } from "../../../lib/credentialStore.js";
|
|
6
|
+
import { AI_PROVIDERS } from "../../../config/aiConfig.js";
|
|
5
7
|
|
|
6
|
-
const setKeyAction = async (
|
|
8
|
+
const setKeyAction = async (apiKeyArg, cmdOptions) => {
|
|
7
9
|
try {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
let provider = cmdOptions.provider;
|
|
11
|
+
let apiKey = apiKeyArg;
|
|
12
|
+
|
|
13
|
+
// Interactive mode if key was not supplied via command line argument
|
|
14
|
+
if (!apiKey) {
|
|
15
|
+
if (!provider) {
|
|
16
|
+
const provChoice = await select({
|
|
17
|
+
message: "Select AI Provider to configure API key for:",
|
|
18
|
+
options: [
|
|
19
|
+
{ value: "gemini", label: "Google Gemini", hint: "AI Studio API key" },
|
|
20
|
+
{ value: "openai", label: "OpenAI", hint: "platform.openai.com key" },
|
|
21
|
+
{ value: "grok", label: "Grok (xAI)", hint: "console.x.ai key" },
|
|
22
|
+
],
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (isCancel(provChoice)) {
|
|
26
|
+
cancel("Operation cancelled.");
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
provider = provChoice;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const provInfo = AI_PROVIDERS[normalizeProviderName(provider)];
|
|
33
|
+
const enteredKey = await password({
|
|
34
|
+
message: `Enter your ${provInfo?.name || provider} API key:`,
|
|
35
|
+
validate(value) {
|
|
36
|
+
if (!value || !value.trim()) return "API key cannot be empty";
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (isCancel(enteredKey)) {
|
|
41
|
+
cancel("Operation cancelled.");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
apiKey = enteredKey;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const norm = normalizeProviderName(provider || "gemini");
|
|
49
|
+
const provInfo = AI_PROVIDERS[norm];
|
|
50
|
+
|
|
51
|
+
await setApiKey(norm, apiKey);
|
|
52
|
+
|
|
53
|
+
console.log(
|
|
54
|
+
chalk.green(`\n✔ ${provInfo?.name || norm} API key saved successfully.`)
|
|
55
|
+
);
|
|
10
56
|
console.log(
|
|
11
57
|
chalk.gray(
|
|
12
58
|
`Stored securely in your OS credential manager (service: ${getCredentialServiceName()}).`
|
|
@@ -19,8 +65,13 @@ const setKeyAction = async (apiKey) => {
|
|
|
19
65
|
};
|
|
20
66
|
|
|
21
67
|
export const setkey = new Command("set-key")
|
|
22
|
-
.description("Store your
|
|
23
|
-
.argument("
|
|
68
|
+
.description("Store your AI provider API key securely in keytar (Gemini, OpenAI, Grok)")
|
|
69
|
+
.argument("[API_KEY]", "Your AI provider API key")
|
|
70
|
+
.option(
|
|
71
|
+
"-p, --provider <provider>",
|
|
72
|
+
"AI provider: gemini (default), openai, or grok",
|
|
73
|
+
"gemini"
|
|
74
|
+
)
|
|
24
75
|
.alias("set")
|
|
25
76
|
.alias("setkey")
|
|
26
77
|
.action(setKeyAction);
|
package/server/src/cli/main.js
CHANGED
|
@@ -12,7 +12,10 @@ import {setkey} from "./commands/config/setkey.js"
|
|
|
12
12
|
import {launch} from "./commands/General/openApp.js"
|
|
13
13
|
import {search} from "./commands/General/searchYoutube.js"
|
|
14
14
|
import {play} from "./commands/General/playSong.js"
|
|
15
|
-
import {
|
|
15
|
+
import { createRequire } from "module";
|
|
16
|
+
const require = createRequire(import.meta.url);
|
|
17
|
+
const packageJson = require("../../../package.json");
|
|
18
|
+
|
|
16
19
|
|
|
17
20
|
const main = async()=>{
|
|
18
21
|
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import "./env.js";
|
|
2
|
+
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
3
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
4
|
+
import { createXai } from "@ai-sdk/xai";
|
|
5
|
+
import { normalizeProviderName, requireApiKeySync } from "../lib/orbitalConfig.js";
|
|
6
|
+
|
|
7
|
+
export const AI_PROVIDERS = {
|
|
8
|
+
gemini: {
|
|
9
|
+
id: "gemini",
|
|
10
|
+
name: "Google Gemini",
|
|
11
|
+
defaultModel: "gemini-2.5-flash",
|
|
12
|
+
envKey: "GOOGLE_GENERATIVE_AI_API_KEY",
|
|
13
|
+
docsUrl: "https://aistudio.google.com/app/apikey",
|
|
14
|
+
models: [
|
|
15
|
+
{
|
|
16
|
+
id: "gemini-2.5-flash",
|
|
17
|
+
name: "Gemini 2.5 Flash",
|
|
18
|
+
hint: "Google (Fast & versatile - Recommended)",
|
|
19
|
+
isDefault: true,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "gemini-2.5-pro",
|
|
23
|
+
name: "Gemini 2.5 Pro",
|
|
24
|
+
hint: "Google (Complex reasoning & large context)",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: "gemini-1.5-flash",
|
|
28
|
+
name: "Gemini 1.5 Flash",
|
|
29
|
+
hint: "Google (Lightweight & efficient)",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: "gemini-1.5-pro",
|
|
33
|
+
name: "Gemini 1.5 Pro",
|
|
34
|
+
hint: "Google (Extended analysis)",
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
openai: {
|
|
39
|
+
id: "openai",
|
|
40
|
+
name: "OpenAI",
|
|
41
|
+
defaultModel: "gpt-4o",
|
|
42
|
+
envKey: "OPENAI_API_KEY",
|
|
43
|
+
docsUrl: "https://platform.openai.com/api-keys",
|
|
44
|
+
models: [
|
|
45
|
+
{
|
|
46
|
+
id: "gpt-4o",
|
|
47
|
+
name: "GPT-4o",
|
|
48
|
+
hint: "OpenAI (Flagship multimodal intelligence)",
|
|
49
|
+
isDefault: true,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "gpt-4o-mini",
|
|
53
|
+
name: "GPT-4o Mini",
|
|
54
|
+
hint: "OpenAI (Fast & cost-effective)",
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
grok: {
|
|
59
|
+
id: "grok",
|
|
60
|
+
name: "Grok (xAI)",
|
|
61
|
+
defaultModel: "grok-2-latest",
|
|
62
|
+
envKey: "XAI_API_KEY",
|
|
63
|
+
docsUrl: "https://console.x.ai/",
|
|
64
|
+
models: [
|
|
65
|
+
{
|
|
66
|
+
id: "grok-2-latest",
|
|
67
|
+
name: "Grok 2",
|
|
68
|
+
hint: "xAI (Frontier model with advanced reasoning)",
|
|
69
|
+
isDefault: true,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: "grok-beta",
|
|
73
|
+
name: "Grok Beta",
|
|
74
|
+
hint: "xAI (Experimental release)",
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Returns options list suitable for @clack/prompts select()
|
|
82
|
+
*/
|
|
83
|
+
export const getModelSelectOptions = () => {
|
|
84
|
+
const options = [];
|
|
85
|
+
for (const provider of Object.values(AI_PROVIDERS)) {
|
|
86
|
+
for (const model of provider.models) {
|
|
87
|
+
options.push({
|
|
88
|
+
value: `${provider.id}:${model.id}`,
|
|
89
|
+
label: `${provider.name} - ${model.name}`,
|
|
90
|
+
hint: model.hint,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return options;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Parse a compound value like "openai:gpt-4o" or separate provider/model inputs
|
|
99
|
+
*/
|
|
100
|
+
export const parseModelChoice = (choice) => {
|
|
101
|
+
if (!choice) return { provider: "gemini", model: "gemini-2.5-flash" };
|
|
102
|
+
if (typeof choice === "object") {
|
|
103
|
+
const provider = normalizeProviderName(choice.provider || "gemini");
|
|
104
|
+
const defaultModel = AI_PROVIDERS[provider]?.defaultModel || "gemini-2.5-flash";
|
|
105
|
+
let model = choice.model || defaultModel;
|
|
106
|
+
if (model.includes("gemini-2.0")) model = "gemini-2.5-flash";
|
|
107
|
+
return {
|
|
108
|
+
provider,
|
|
109
|
+
model,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (typeof choice === "string" && choice.includes(":")) {
|
|
114
|
+
const [p, m] = choice.split(":");
|
|
115
|
+
const provider = normalizeProviderName(p);
|
|
116
|
+
const model = m.includes("gemini-2.0") ? "gemini-2.5-flash" : m;
|
|
117
|
+
return { provider, model };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// If only provider name is given
|
|
121
|
+
const provider = normalizeProviderName(choice);
|
|
122
|
+
return {
|
|
123
|
+
provider,
|
|
124
|
+
model: AI_PROVIDERS[provider]?.defaultModel || choice,
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
export const getModelDisplayName = (provider, modelId) => {
|
|
130
|
+
const norm = normalizeProviderName(provider);
|
|
131
|
+
const provInfo = AI_PROVIDERS[norm];
|
|
132
|
+
if (!provInfo) return `${provider} (${modelId})`;
|
|
133
|
+
const modelInfo = provInfo.models.find((m) => m.id === modelId);
|
|
134
|
+
return modelInfo ? `${provInfo.name} (${modelInfo.name})` : `${provInfo.name} (${modelId})`;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Creates a language model instance for Vercel AI SDK
|
|
139
|
+
*/
|
|
140
|
+
export const createModelInstance = (provider, modelName, apiKey = null) => {
|
|
141
|
+
const norm = normalizeProviderName(provider);
|
|
142
|
+
const key = apiKey || requireApiKeySync(norm);
|
|
143
|
+
|
|
144
|
+
switch (norm) {
|
|
145
|
+
case "openai": {
|
|
146
|
+
const openai = createOpenAI({ apiKey: key });
|
|
147
|
+
return openai(modelName);
|
|
148
|
+
}
|
|
149
|
+
case "grok": {
|
|
150
|
+
const xai = createXai({ apiKey: key });
|
|
151
|
+
return xai(modelName);
|
|
152
|
+
}
|
|
153
|
+
case "gemini":
|
|
154
|
+
default: {
|
|
155
|
+
const google = createGoogleGenerativeAI({ apiKey: key });
|
|
156
|
+
return google(modelName);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
};
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { google } from "@ai-sdk/google";
|
|
2
2
|
import chalk from "chalk";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
normalizeProviderName,
|
|
5
|
+
requireApiKeySync,
|
|
6
|
+
hasApiKeySync,
|
|
7
|
+
} from "../lib/orbitalConfig.js";
|
|
4
8
|
|
|
5
9
|
export const availableTools = [
|
|
10
|
+
// Google Gemini Native Tools
|
|
6
11
|
{
|
|
7
12
|
id: "google_search",
|
|
8
13
|
name: "Google Search",
|
|
9
14
|
description:
|
|
10
15
|
"Access the latest information using Google Search. Useful for current events, news, and real-time information",
|
|
16
|
+
provider: "gemini",
|
|
11
17
|
getTool: () => google.tools.googleSearch({}),
|
|
12
18
|
enabled: false,
|
|
13
19
|
},
|
|
@@ -16,6 +22,7 @@ export const availableTools = [
|
|
|
16
22
|
name: "Code Execution",
|
|
17
23
|
description:
|
|
18
24
|
"Generate and execute Python code to perform calculations, solve problems or provide accurate information",
|
|
25
|
+
provider: "gemini",
|
|
19
26
|
getTool: () => google.tools.codeExecution({}),
|
|
20
27
|
enabled: false,
|
|
21
28
|
},
|
|
@@ -24,45 +31,41 @@ export const availableTools = [
|
|
|
24
31
|
name: "URL Context",
|
|
25
32
|
description:
|
|
26
33
|
"Provide specific URLs that you want the model to analyse directly from the prompt. Supports up to 20 URLs per request.",
|
|
34
|
+
provider: "gemini",
|
|
27
35
|
getTool: () => google.tools.urlContext({}),
|
|
28
36
|
enabled: false,
|
|
29
37
|
},
|
|
30
38
|
];
|
|
31
39
|
|
|
32
|
-
export const
|
|
40
|
+
export const getToolsForProvider = (provider = "gemini") => {
|
|
41
|
+
const norm = normalizeProviderName(provider);
|
|
42
|
+
return availableTools.filter(
|
|
43
|
+
(tool) => tool.provider === "all" || tool.provider === norm
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const getEnabledTools = (provider = "gemini") => {
|
|
48
|
+
const norm = normalizeProviderName(provider);
|
|
33
49
|
const tools = {};
|
|
34
50
|
|
|
35
51
|
try {
|
|
36
|
-
const
|
|
37
|
-
if (enabledToolCount > 0 && !process.env.GOOGLE_GENERATIVE_AI_API_KEY) {
|
|
38
|
-
|
|
39
|
-
requireGeminiApiKeySync();
|
|
40
|
-
}
|
|
52
|
+
const providerTools = getToolsForProvider(norm);
|
|
41
53
|
|
|
42
|
-
for (const toolConfig of
|
|
54
|
+
for (const toolConfig of providerTools) {
|
|
43
55
|
if (toolConfig.enabled) {
|
|
56
|
+
if (toolConfig.provider === "gemini" && !hasApiKeySync("gemini")) {
|
|
57
|
+
requireApiKeySync("gemini");
|
|
58
|
+
}
|
|
44
59
|
tools[toolConfig.id] = toolConfig.getTool();
|
|
45
60
|
}
|
|
46
61
|
}
|
|
47
62
|
|
|
48
|
-
if (Object.keys(tools).length > 0) {
|
|
49
|
-
console.log(
|
|
50
|
-
chalk.gray(`[DEBUG] Enabled tools: ${Object.keys(tools).join(", ")}`)
|
|
51
|
-
);
|
|
52
|
-
} else {
|
|
53
|
-
console.log(chalk.yellow(`[DEBUG] No tools enabled`));
|
|
54
|
-
}
|
|
55
|
-
|
|
56
63
|
return Object.keys(tools).length > 0 ? tools : undefined;
|
|
57
64
|
} catch (error) {
|
|
58
65
|
console.error(
|
|
59
66
|
chalk.red(`[ERROR] Failed to initialize tools:`),
|
|
60
67
|
error?.message || error
|
|
61
68
|
);
|
|
62
|
-
console.error(
|
|
63
|
-
chalk.yellow(`Make sure you have @ai-sdk/google version 2.0+ installed`)
|
|
64
|
-
);
|
|
65
|
-
console.error(chalk.yellow(`Run: npm install @ai-sdk/google@latest`));
|
|
66
69
|
return undefined;
|
|
67
70
|
}
|
|
68
71
|
};
|
|
@@ -72,49 +75,27 @@ export const toggleTool = (toolId) => {
|
|
|
72
75
|
|
|
73
76
|
if (tool) {
|
|
74
77
|
tool.enabled = !tool.enabled;
|
|
75
|
-
console.log(
|
|
76
|
-
chalk.gray(`[DEBUG] Tool ${toolId} toggled to ${tool.enabled}`)
|
|
77
|
-
);
|
|
78
78
|
return tool.enabled;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
console.log(chalk.red(`[DEBUG] Tool ${toolId} not found`));
|
|
82
81
|
return false;
|
|
83
82
|
};
|
|
84
83
|
|
|
85
84
|
export const toogleTool = toggleTool;
|
|
86
85
|
|
|
87
86
|
export const enableTools = (toolIds = []) => {
|
|
88
|
-
console.log(chalk.gray(`[DEBUG] enableTools called with:`), toolIds);
|
|
89
|
-
|
|
90
87
|
availableTools.forEach((tool) => {
|
|
91
|
-
const wasEnabled = tool.enabled;
|
|
92
88
|
tool.enabled = toolIds.includes(tool.id);
|
|
93
|
-
|
|
94
|
-
if (tool.enabled !== wasEnabled) {
|
|
95
|
-
console.log(
|
|
96
|
-
chalk.gray(`[DEBUG] ${tool.id}: ${wasEnabled} -> ${tool.enabled}`)
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
89
|
});
|
|
100
|
-
|
|
101
|
-
const enabledCount = availableTools.filter((t) => t.enabled).length;
|
|
102
|
-
console.log(
|
|
103
|
-
chalk.gray(
|
|
104
|
-
`[DEBUG] Total tools enabled: ${enabledCount} / ${availableTools.length}`
|
|
105
|
-
)
|
|
106
|
-
);
|
|
107
90
|
};
|
|
108
91
|
|
|
109
92
|
export const getEnabledToolNames = () => {
|
|
110
|
-
|
|
111
|
-
console.log(chalk.gray(`[DEBUG] getEnabledToolNames returning:`), names);
|
|
112
|
-
return names;
|
|
93
|
+
return availableTools.filter((t) => t.enabled).map((t) => t.name);
|
|
113
94
|
};
|
|
114
95
|
|
|
115
96
|
export const resetTools = () => {
|
|
116
97
|
availableTools.forEach((tool) => {
|
|
117
98
|
tool.enabled = false;
|
|
118
99
|
});
|
|
119
|
-
console.log(chalk.gray(`[DEBUG] All tools have been reset (disabled)`));
|
|
120
100
|
};
|
|
101
|
+
|