@cosmicstack/mercury-agent 1.1.2 → 1.1.4
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/dist/index.js +140 -29
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -80,7 +80,7 @@ function getDefaultConfig() {
|
|
|
80
80
|
ollamaCloud: {
|
|
81
81
|
name: "ollamaCloud",
|
|
82
82
|
apiKey: getEnv("OLLAMA_CLOUD_API_KEY", ""),
|
|
83
|
-
baseUrl: getEnv("OLLAMA_CLOUD_BASE_URL", "https://ollama.com/
|
|
83
|
+
baseUrl: getEnv("OLLAMA_CLOUD_BASE_URL", "https://ollama.com/v1"),
|
|
84
84
|
model: getEnv("OLLAMA_CLOUD_MODEL", "gpt-oss:120b"),
|
|
85
85
|
enabled: getEnvBool("OLLAMA_CLOUD_ENABLED", true)
|
|
86
86
|
},
|
|
@@ -91,6 +91,13 @@ function getDefaultConfig() {
|
|
|
91
91
|
model: getEnv("OLLAMA_LOCAL_MODEL", "gpt-oss:20b"),
|
|
92
92
|
enabled: getEnvBool("OLLAMA_LOCAL_ENABLED", false)
|
|
93
93
|
},
|
|
94
|
+
openaiCompat: {
|
|
95
|
+
name: "openaiCompat",
|
|
96
|
+
apiKey: getEnv("OPENAI_COMPAT_API_KEY", ""),
|
|
97
|
+
baseUrl: getEnv("OPENAI_COMPAT_BASE_URL", ""),
|
|
98
|
+
model: getEnv("OPENAI_COMPAT_MODEL", ""),
|
|
99
|
+
enabled: getEnvBool("OPENAI_COMPAT_ENABLED", false)
|
|
100
|
+
},
|
|
94
101
|
mimo: {
|
|
95
102
|
name: "mimo",
|
|
96
103
|
apiKey: getEnv("MIMO_API_KEY", ""),
|
|
@@ -145,7 +152,9 @@ function loadConfig() {
|
|
|
145
152
|
const raw = readFileSync(CONFIG_PATH, "utf-8");
|
|
146
153
|
const fileConfig = parseYaml(raw);
|
|
147
154
|
const defaults = getDefaultConfig();
|
|
148
|
-
return
|
|
155
|
+
return migrateLegacyOllamaCloudBaseUrl(
|
|
156
|
+
migrateLegacyTelegramAccess(deepMerge(defaults, fileConfig))
|
|
157
|
+
);
|
|
149
158
|
}
|
|
150
159
|
return migrateLegacyTelegramAccess(getDefaultConfig());
|
|
151
160
|
}
|
|
@@ -189,6 +198,12 @@ function isProviderConfigured(provider) {
|
|
|
189
198
|
if (provider.name === "ollamaLocal") {
|
|
190
199
|
return provider.baseUrl.length > 0 && provider.model.length > 0;
|
|
191
200
|
}
|
|
201
|
+
if (provider.name === "ollamaCloud") {
|
|
202
|
+
return provider.apiKey.length > 0 && provider.baseUrl.length > 0;
|
|
203
|
+
}
|
|
204
|
+
if (provider.name === "openaiCompat") {
|
|
205
|
+
return provider.baseUrl.length > 0 && provider.model.length > 0;
|
|
206
|
+
}
|
|
192
207
|
return provider.apiKey.length > 0;
|
|
193
208
|
}
|
|
194
209
|
function getTelegramApprovedUsers(config) {
|
|
@@ -330,6 +345,13 @@ function migrateLegacyTelegramAccess(config) {
|
|
|
330
345
|
delete telegram.pairedUsername;
|
|
331
346
|
return config;
|
|
332
347
|
}
|
|
348
|
+
function migrateLegacyOllamaCloudBaseUrl(config) {
|
|
349
|
+
if (config.providers.ollamaCloud.baseUrl === "https://ollama.com/api") {
|
|
350
|
+
config.providers.ollamaCloud.baseUrl = "https://ollama.com/v1";
|
|
351
|
+
saveConfig(config);
|
|
352
|
+
}
|
|
353
|
+
return config;
|
|
354
|
+
}
|
|
333
355
|
|
|
334
356
|
// src/utils/logger.ts
|
|
335
357
|
import pino from "pino";
|
|
@@ -1531,15 +1553,15 @@ var OpenAICompatProvider = class extends BaseProvider {
|
|
|
1531
1553
|
model;
|
|
1532
1554
|
client;
|
|
1533
1555
|
modelInstance;
|
|
1534
|
-
constructor(config) {
|
|
1556
|
+
constructor(config, { useChatApi } = {}) {
|
|
1535
1557
|
super(config);
|
|
1536
1558
|
this.name = config.name;
|
|
1537
1559
|
this.model = config.model;
|
|
1538
1560
|
this.client = createOpenAI({
|
|
1539
|
-
apiKey: config.apiKey,
|
|
1561
|
+
apiKey: config.apiKey || "no-key",
|
|
1540
1562
|
baseURL: config.baseUrl
|
|
1541
1563
|
});
|
|
1542
|
-
this.modelInstance = this.client(config.model);
|
|
1564
|
+
this.modelInstance = useChatApi ? this.client.chat(config.model) : this.client(config.model);
|
|
1543
1565
|
}
|
|
1544
1566
|
async generateText(prompt, systemPrompt) {
|
|
1545
1567
|
const result = await generateText({
|
|
@@ -1686,7 +1708,7 @@ var OllamaProvider = class extends BaseProvider {
|
|
|
1686
1708
|
if (this.name === "ollamaLocal") {
|
|
1687
1709
|
return this.config.baseUrl.length > 0 && this.config.model.length > 0;
|
|
1688
1710
|
}
|
|
1689
|
-
return this.config.apiKey.length > 0;
|
|
1711
|
+
return this.config.apiKey.length > 0 && this.config.baseUrl.length > 0;
|
|
1690
1712
|
}
|
|
1691
1713
|
getModelInstance() {
|
|
1692
1714
|
return this.modelInstance;
|
|
@@ -1737,6 +1759,7 @@ var ProviderRegistry = class {
|
|
|
1737
1759
|
config.providers.grok,
|
|
1738
1760
|
config.providers.ollamaCloud,
|
|
1739
1761
|
config.providers.ollamaLocal,
|
|
1762
|
+
config.providers.openaiCompat,
|
|
1740
1763
|
config.providers.mimo,
|
|
1741
1764
|
config.providers.mimoTokenPlan
|
|
1742
1765
|
];
|
|
@@ -1748,8 +1771,12 @@ var ProviderRegistry = class {
|
|
|
1748
1771
|
provider = new AnthropicProvider(pc);
|
|
1749
1772
|
} else if (pc.name === "deepseek") {
|
|
1750
1773
|
provider = new DeepSeekProvider(pc);
|
|
1751
|
-
} else if (pc.name === "
|
|
1774
|
+
} else if (pc.name === "ollamaLocal") {
|
|
1752
1775
|
provider = new OllamaProvider(pc);
|
|
1776
|
+
} else if (pc.name === "ollamaCloud") {
|
|
1777
|
+
provider = new OpenAICompatProvider(pc, { useChatApi: true });
|
|
1778
|
+
} else if (pc.name === "openaiCompat") {
|
|
1779
|
+
provider = new OpenAICompatProvider(pc, { useChatApi: true });
|
|
1753
1780
|
} else if (pc.name === "mimo" || pc.name === "mimoTokenPlan") {
|
|
1754
1781
|
provider = new MiMoProvider(pc);
|
|
1755
1782
|
} else {
|
|
@@ -8156,6 +8183,7 @@ var MIMO_PREFERRED_MODELS = [
|
|
|
8156
8183
|
"mimo-v2-flash"
|
|
8157
8184
|
];
|
|
8158
8185
|
var MIMO_TOKEN_PLAN_PREFERRED_MODELS = MIMO_PREFERRED_MODELS;
|
|
8186
|
+
var OPENAI_COMPAT_PREFERRED_MODELS = [];
|
|
8159
8187
|
var ProviderModelFetchError = class extends Error {
|
|
8160
8188
|
constructor(message) {
|
|
8161
8189
|
super(message);
|
|
@@ -8211,6 +8239,7 @@ function chooseRecommendedModel(provider, models, currentModel) {
|
|
|
8211
8239
|
grok: GROK_PREFERRED_MODELS,
|
|
8212
8240
|
ollamaCloud: OLLAMA_CLOUD_PREFERRED_MODELS,
|
|
8213
8241
|
ollamaLocal: OLLAMA_LOCAL_PREFERRED_MODELS,
|
|
8242
|
+
openaiCompat: OPENAI_COMPAT_PREFERRED_MODELS,
|
|
8214
8243
|
mimo: MIMO_PREFERRED_MODELS,
|
|
8215
8244
|
mimoTokenPlan: MIMO_TOKEN_PLAN_PREFERRED_MODELS
|
|
8216
8245
|
};
|
|
@@ -8237,6 +8266,7 @@ function buildModelCatalog(provider, models, currentModel) {
|
|
|
8237
8266
|
grok: GROK_PREFERRED_MODELS,
|
|
8238
8267
|
ollamaCloud: OLLAMA_CLOUD_PREFERRED_MODELS,
|
|
8239
8268
|
ollamaLocal: OLLAMA_LOCAL_PREFERRED_MODELS,
|
|
8269
|
+
openaiCompat: OPENAI_COMPAT_PREFERRED_MODELS,
|
|
8240
8270
|
mimo: MIMO_PREFERRED_MODELS,
|
|
8241
8271
|
mimoTokenPlan: MIMO_TOKEN_PLAN_PREFERRED_MODELS
|
|
8242
8272
|
};
|
|
@@ -8248,19 +8278,32 @@ function buildModelCatalog(provider, models, currentModel) {
|
|
|
8248
8278
|
};
|
|
8249
8279
|
}
|
|
8250
8280
|
async function fetchOpenAICompatModels(provider, config) {
|
|
8281
|
+
const headers = {};
|
|
8282
|
+
if (config.apiKey) {
|
|
8283
|
+
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
8284
|
+
}
|
|
8285
|
+
let errorMessage;
|
|
8286
|
+
if (provider === "grok") {
|
|
8287
|
+
errorMessage = "Mercury could not fetch models for this Grok key. Please re-enter it.";
|
|
8288
|
+
} else if (provider === "deepseek") {
|
|
8289
|
+
errorMessage = "Mercury could not fetch models for this DeepSeek key. Please re-enter it.";
|
|
8290
|
+
} else if (provider === "openaiCompat") {
|
|
8291
|
+
errorMessage = "Mercury could not fetch models from this server. Please check the base URL and try again.";
|
|
8292
|
+
} else {
|
|
8293
|
+
errorMessage = "Mercury could not fetch models for this OpenAI key. Please re-enter it.";
|
|
8294
|
+
}
|
|
8251
8295
|
const data = await fetchJson(
|
|
8252
8296
|
`${trimTrailingSlash(config.baseUrl)}/models`,
|
|
8253
|
-
{
|
|
8254
|
-
|
|
8255
|
-
Authorization: `Bearer ${config.apiKey}`
|
|
8256
|
-
}
|
|
8257
|
-
},
|
|
8258
|
-
`Mercury could not fetch models for this ${provider === "grok" ? "Grok" : provider === "deepseek" ? "DeepSeek" : "OpenAI"} key. Please re-enter it.`
|
|
8297
|
+
{ headers },
|
|
8298
|
+
errorMessage
|
|
8259
8299
|
);
|
|
8260
8300
|
const ids = (data.data ?? []).map((model) => model.id?.trim() ?? "").filter((id) => {
|
|
8261
8301
|
if (provider === "deepseek") {
|
|
8262
8302
|
return id.startsWith("deepseek-");
|
|
8263
8303
|
}
|
|
8304
|
+
if (provider === "openaiCompat") {
|
|
8305
|
+
return id.length > 0;
|
|
8306
|
+
}
|
|
8264
8307
|
return isOpenAIChatModel(id);
|
|
8265
8308
|
});
|
|
8266
8309
|
return buildModelCatalog(provider, ids, config.model);
|
|
@@ -8292,17 +8335,27 @@ async function fetchGrokModels(config) {
|
|
|
8292
8335
|
const ids = (data.data ?? []).filter((model) => model.output_modalities?.includes("text") || model.output_modalities == null).map((model) => model.id?.trim() ?? "").filter((id) => id.startsWith("grok-"));
|
|
8293
8336
|
return buildModelCatalog("grok", ids, config.model);
|
|
8294
8337
|
}
|
|
8295
|
-
async function
|
|
8296
|
-
const headers = config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : void 0;
|
|
8338
|
+
async function fetchOllamaCloudModels(config) {
|
|
8297
8339
|
const data = await fetchJson(
|
|
8298
|
-
`${trimTrailingSlash(config.baseUrl)}/
|
|
8340
|
+
`${trimTrailingSlash(config.baseUrl)}/models`,
|
|
8299
8341
|
{
|
|
8300
|
-
headers
|
|
8342
|
+
headers: {
|
|
8343
|
+
Authorization: `Bearer ${config.apiKey}`
|
|
8344
|
+
}
|
|
8301
8345
|
},
|
|
8302
|
-
|
|
8346
|
+
"Mercury could not fetch models for this Ollama Cloud key. Please re-enter it."
|
|
8347
|
+
);
|
|
8348
|
+
const ids = (data.data ?? []).map((model) => model.id?.trim() ?? "").filter(Boolean);
|
|
8349
|
+
return buildModelCatalog("ollamaCloud", ids, config.model);
|
|
8350
|
+
}
|
|
8351
|
+
async function fetchOllamaLocalModels(config) {
|
|
8352
|
+
const data = await fetchJson(
|
|
8353
|
+
`${trimTrailingSlash(config.baseUrl)}/tags`,
|
|
8354
|
+
{},
|
|
8355
|
+
"Mercury could not fetch models from this Ollama Local server. Please check the base URL and try again."
|
|
8303
8356
|
);
|
|
8304
8357
|
const ids = (data.models ?? []).map((model) => model.model?.trim() || model.name?.trim() || "").filter(Boolean);
|
|
8305
|
-
return buildModelCatalog(
|
|
8358
|
+
return buildModelCatalog("ollamaLocal", ids, config.model);
|
|
8306
8359
|
}
|
|
8307
8360
|
async function fetchMiMoModels(config) {
|
|
8308
8361
|
const data = await fetchJson(
|
|
@@ -8343,8 +8396,14 @@ async function fetchProviderModelCatalog(provider, config) {
|
|
|
8343
8396
|
if (provider === "grok") {
|
|
8344
8397
|
return fetchGrokModels(config);
|
|
8345
8398
|
}
|
|
8346
|
-
if (provider === "ollamaCloud"
|
|
8347
|
-
return
|
|
8399
|
+
if (provider === "ollamaCloud") {
|
|
8400
|
+
return fetchOllamaCloudModels(config);
|
|
8401
|
+
}
|
|
8402
|
+
if (provider === "ollamaLocal") {
|
|
8403
|
+
return fetchOllamaLocalModels(config);
|
|
8404
|
+
}
|
|
8405
|
+
if (provider === "openaiCompat") {
|
|
8406
|
+
return fetchOpenAICompatModels(provider, config);
|
|
8348
8407
|
}
|
|
8349
8408
|
if (provider === "mimo") {
|
|
8350
8409
|
return fetchMiMoModels(config);
|
|
@@ -8410,6 +8469,7 @@ var PROVIDER_OPTIONS = [
|
|
|
8410
8469
|
{ key: "grok", label: "Grok (xAI)" },
|
|
8411
8470
|
{ key: "ollamaCloud", label: "Ollama Cloud" },
|
|
8412
8471
|
{ key: "ollamaLocal", label: "Ollama Local" },
|
|
8472
|
+
{ key: "openaiCompat", label: "OpenAI Compilations" },
|
|
8413
8473
|
{ key: "mimo", label: "MiMo (Xiaomi)" },
|
|
8414
8474
|
{ key: "mimoTokenPlan", label: "MiMo Token Plan (Xiaomi)" }
|
|
8415
8475
|
];
|
|
@@ -8635,6 +8695,40 @@ async function promptOllamaLocalModelSelection(config) {
|
|
|
8635
8695
|
}
|
|
8636
8696
|
}
|
|
8637
8697
|
}
|
|
8698
|
+
async function promptOpenAICompatSetup(config, isReconfig) {
|
|
8699
|
+
const existingConfig = config.providers.openaiCompat;
|
|
8700
|
+
const baseUrl = await promptValidatedValue(
|
|
8701
|
+
chalk7.white(` Server base URL${isReconfig && existingConfig.baseUrl ? ` [${existingConfig.baseUrl}]` : ""}: `),
|
|
8702
|
+
validateBaseUrl,
|
|
8703
|
+
existingConfig.baseUrl
|
|
8704
|
+
);
|
|
8705
|
+
if (!baseUrl) return { skipped: true };
|
|
8706
|
+
const apiKeyPrompt = isReconfig && existingConfig.apiKey ? chalk7.white(` API key (optional, press Enter to keep current) [${maskKey(existingConfig.apiKey)}]: `) : chalk7.white(" API key (optional, press Enter to skip): ");
|
|
8707
|
+
const apiKey = await ask(apiKeyPrompt);
|
|
8708
|
+
const resolvedApiKey = apiKey || existingConfig.apiKey || "";
|
|
8709
|
+
console.log(chalk7.dim(" Fetching models from server..."));
|
|
8710
|
+
try {
|
|
8711
|
+
const catalog = await fetchProviderModelCatalog("openaiCompat", {
|
|
8712
|
+
...existingConfig,
|
|
8713
|
+
baseUrl,
|
|
8714
|
+
apiKey: resolvedApiKey
|
|
8715
|
+
});
|
|
8716
|
+
const model = await chooseProviderModel(
|
|
8717
|
+
"OpenAI Compilations",
|
|
8718
|
+
catalog.recommendedModel,
|
|
8719
|
+
catalog.models
|
|
8720
|
+
);
|
|
8721
|
+
return { baseUrl, apiKey: resolvedApiKey, model, skipped: false };
|
|
8722
|
+
} catch {
|
|
8723
|
+
console.log(chalk7.yellow(" Could not fetch models from this server. You can enter the model name manually."));
|
|
8724
|
+
const model = await promptValidatedValue(
|
|
8725
|
+
chalk7.white(" Model name: "),
|
|
8726
|
+
validateModelName
|
|
8727
|
+
);
|
|
8728
|
+
if (!model) return { baseUrl, apiKey: resolvedApiKey, model: existingConfig.model, skipped: false };
|
|
8729
|
+
return { baseUrl, apiKey: resolvedApiKey, model, skipped: false };
|
|
8730
|
+
}
|
|
8731
|
+
}
|
|
8638
8732
|
async function promptValidatedValue(prompt, validator, existingValue, options) {
|
|
8639
8733
|
while (true) {
|
|
8640
8734
|
const value = await ask(prompt);
|
|
@@ -8868,6 +8962,18 @@ async function configure(existingConfig) {
|
|
|
8868
8962
|
}
|
|
8869
8963
|
continue;
|
|
8870
8964
|
}
|
|
8965
|
+
if (provider === "openaiCompat") {
|
|
8966
|
+
const result = await promptOpenAICompatSetup(config, isReconfig);
|
|
8967
|
+
if (!result.skipped && result.baseUrl && result.model) {
|
|
8968
|
+
config.providers.openaiCompat.baseUrl = result.baseUrl;
|
|
8969
|
+
config.providers.openaiCompat.model = result.model;
|
|
8970
|
+
config.providers.openaiCompat.enabled = true;
|
|
8971
|
+
if (result.apiKey) {
|
|
8972
|
+
config.providers.openaiCompat.apiKey = result.apiKey;
|
|
8973
|
+
}
|
|
8974
|
+
}
|
|
8975
|
+
continue;
|
|
8976
|
+
}
|
|
8871
8977
|
if (provider === "mimo") {
|
|
8872
8978
|
const mask = isReconfig && config.providers.mimo.apiKey ? ` [${maskKey(config.providers.mimo.apiKey)}]` : "";
|
|
8873
8979
|
const result = await promptApiKeyWithModelSelection(
|
|
@@ -9054,16 +9160,21 @@ async function runAgent(isDaemon = false) {
|
|
|
9054
9160
|
process.exit(1);
|
|
9055
9161
|
}
|
|
9056
9162
|
const available = providers.listAvailable();
|
|
9057
|
-
const
|
|
9058
|
-
const
|
|
9059
|
-
const key = provider;
|
|
9060
|
-
return `${getProviderLabel(key)}: ${config.providers[key].model}`;
|
|
9061
|
-
});
|
|
9163
|
+
const defaultProvider = config.providers.default;
|
|
9164
|
+
const defaultModel = config.providers[defaultProvider]?.model ?? "unknown";
|
|
9062
9165
|
if (!isDaemon) {
|
|
9063
|
-
|
|
9064
|
-
|
|
9166
|
+
const providerSummary = available.map((provider) => {
|
|
9167
|
+
const key = provider;
|
|
9168
|
+
const label = getProviderLabel(key);
|
|
9169
|
+
const model = config.providers[key]?.model ?? "?";
|
|
9170
|
+
const marker = key === defaultProvider ? " \u2190 default" : "";
|
|
9171
|
+
return `${label}: ${model}${marker}`;
|
|
9172
|
+
});
|
|
9173
|
+
console.log("");
|
|
9174
|
+
console.log(chalk7.bgMagenta.black.bold(` \u26A1 ${getProviderLabel(defaultProvider)} \xB7 ${defaultModel} `));
|
|
9175
|
+
console.log(chalk7.dim(` Providers: ${providerSummary.join(" \xB7 ")}`));
|
|
9065
9176
|
} else {
|
|
9066
|
-
logger.info({ providers: available }, "Providers loaded");
|
|
9177
|
+
logger.info({ providers: available, default: defaultProvider }, "Providers loaded");
|
|
9067
9178
|
}
|
|
9068
9179
|
const skillLoader = new SkillLoader();
|
|
9069
9180
|
const skills = skillLoader.discover();
|