@cosmicstack/mercury-agent 1.1.1 → 1.1.3

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 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/api"),
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
  },
@@ -90,6 +90,20 @@ function getDefaultConfig() {
90
90
  baseUrl: getEnv("OLLAMA_LOCAL_BASE_URL", "http://127.0.0.1:11434/api"),
91
91
  model: getEnv("OLLAMA_LOCAL_MODEL", "gpt-oss:20b"),
92
92
  enabled: getEnvBool("OLLAMA_LOCAL_ENABLED", false)
93
+ },
94
+ mimo: {
95
+ name: "mimo",
96
+ apiKey: getEnv("MIMO_API_KEY", ""),
97
+ baseUrl: getEnv("MIMO_BASE_URL", "https://api.xiaomimimo.com/v1"),
98
+ model: getEnv("MIMO_MODEL", "mimo-v2.5-pro"),
99
+ enabled: getEnvBool("MIMO_ENABLED", true)
100
+ },
101
+ mimoTokenPlan: {
102
+ name: "mimoTokenPlan",
103
+ apiKey: getEnv("MIMO_TOKEN_PLAN_API_KEY", ""),
104
+ baseUrl: getEnv("MIMO_TOKEN_PLAN_BASE_URL", "https://token-plan-cn.xiaomimimo.com/v1"),
105
+ model: getEnv("MIMO_TOKEN_PLAN_MODEL", "mimo-v2.5-pro"),
106
+ enabled: getEnvBool("MIMO_TOKEN_PLAN_ENABLED", false)
93
107
  }
94
108
  },
95
109
  channels: {
@@ -131,7 +145,9 @@ function loadConfig() {
131
145
  const raw = readFileSync(CONFIG_PATH, "utf-8");
132
146
  const fileConfig = parseYaml(raw);
133
147
  const defaults = getDefaultConfig();
134
- return migrateLegacyTelegramAccess(deepMerge(defaults, fileConfig));
148
+ return migrateLegacyOllamaCloudBaseUrl(
149
+ migrateLegacyTelegramAccess(deepMerge(defaults, fileConfig))
150
+ );
135
151
  }
136
152
  return migrateLegacyTelegramAccess(getDefaultConfig());
137
153
  }
@@ -175,6 +191,9 @@ function isProviderConfigured(provider) {
175
191
  if (provider.name === "ollamaLocal") {
176
192
  return provider.baseUrl.length > 0 && provider.model.length > 0;
177
193
  }
194
+ if (provider.name === "ollamaCloud") {
195
+ return provider.apiKey.length > 0 && provider.baseUrl.length > 0;
196
+ }
178
197
  return provider.apiKey.length > 0;
179
198
  }
180
199
  function getTelegramApprovedUsers(config) {
@@ -316,6 +335,13 @@ function migrateLegacyTelegramAccess(config) {
316
335
  delete telegram.pairedUsername;
317
336
  return config;
318
337
  }
338
+ function migrateLegacyOllamaCloudBaseUrl(config) {
339
+ if (config.providers.ollamaCloud.baseUrl === "https://ollama.com/api") {
340
+ config.providers.ollamaCloud.baseUrl = "https://ollama.com/v1";
341
+ saveConfig(config);
342
+ }
343
+ return config;
344
+ }
319
345
 
320
346
  // src/utils/logger.ts
321
347
  import pino from "pino";
@@ -1517,7 +1543,7 @@ var OpenAICompatProvider = class extends BaseProvider {
1517
1543
  model;
1518
1544
  client;
1519
1545
  modelInstance;
1520
- constructor(config) {
1546
+ constructor(config, { useChatApi } = {}) {
1521
1547
  super(config);
1522
1548
  this.name = config.name;
1523
1549
  this.model = config.model;
@@ -1525,7 +1551,7 @@ var OpenAICompatProvider = class extends BaseProvider {
1525
1551
  apiKey: config.apiKey,
1526
1552
  baseURL: config.baseUrl
1527
1553
  });
1528
- this.modelInstance = this.client(config.model);
1554
+ this.modelInstance = useChatApi ? this.client.chat(config.model) : this.client(config.model);
1529
1555
  }
1530
1556
  async generateText(prompt, systemPrompt) {
1531
1557
  const result = await generateText({
@@ -1672,6 +1698,36 @@ var OllamaProvider = class extends BaseProvider {
1672
1698
  if (this.name === "ollamaLocal") {
1673
1699
  return this.config.baseUrl.length > 0 && this.config.model.length > 0;
1674
1700
  }
1701
+ return this.config.apiKey.length > 0 && this.config.baseUrl.length > 0;
1702
+ }
1703
+ getModelInstance() {
1704
+ return this.modelInstance;
1705
+ }
1706
+ };
1707
+
1708
+ // src/providers/mimo.ts
1709
+ import { createOpenAI as createOpenAI2 } from "@ai-sdk/openai";
1710
+ var MiMoProvider = class extends BaseProvider {
1711
+ name;
1712
+ model;
1713
+ modelInstance;
1714
+ constructor(config) {
1715
+ super(config);
1716
+ this.name = config.name;
1717
+ this.model = config.model;
1718
+ const client = createOpenAI2({
1719
+ apiKey: config.apiKey,
1720
+ baseURL: config.baseUrl
1721
+ });
1722
+ this.modelInstance = client.chat(config.model);
1723
+ }
1724
+ async generateText(_prompt, _systemPrompt) {
1725
+ throw new Error("Use getModelInstance() with the AI SDK agent loop");
1726
+ }
1727
+ async *streamText(_prompt, _systemPrompt) {
1728
+ throw new Error("Use getModelInstance() with the AI SDK agent loop");
1729
+ }
1730
+ isAvailable() {
1675
1731
  return this.config.apiKey.length > 0;
1676
1732
  }
1677
1733
  getModelInstance() {
@@ -1692,7 +1748,9 @@ var ProviderRegistry = class {
1692
1748
  config.providers.anthropic,
1693
1749
  config.providers.grok,
1694
1750
  config.providers.ollamaCloud,
1695
- config.providers.ollamaLocal
1751
+ config.providers.ollamaLocal,
1752
+ config.providers.mimo,
1753
+ config.providers.mimoTokenPlan
1696
1754
  ];
1697
1755
  for (const pc of entries) {
1698
1756
  if (!isProviderConfigured(pc)) continue;
@@ -1702,8 +1760,12 @@ var ProviderRegistry = class {
1702
1760
  provider = new AnthropicProvider(pc);
1703
1761
  } else if (pc.name === "deepseek") {
1704
1762
  provider = new DeepSeekProvider(pc);
1705
- } else if (pc.name === "ollamaCloud" || pc.name === "ollamaLocal") {
1763
+ } else if (pc.name === "ollamaLocal") {
1706
1764
  provider = new OllamaProvider(pc);
1765
+ } else if (pc.name === "ollamaCloud") {
1766
+ provider = new OpenAICompatProvider(pc, { useChatApi: true });
1767
+ } else if (pc.name === "mimo" || pc.name === "mimoTokenPlan") {
1768
+ provider = new MiMoProvider(pc);
1707
1769
  } else {
1708
1770
  provider = new OpenAICompatProvider(pc);
1709
1771
  }
@@ -8100,6 +8162,14 @@ var OLLAMA_LOCAL_PREFERRED_MODELS = [
8100
8162
  "gpt-oss:20b",
8101
8163
  "gpt-oss:120b"
8102
8164
  ];
8165
+ var MIMO_PREFERRED_MODELS = [
8166
+ "mimo-v2.5-pro",
8167
+ "mimo-v2.5",
8168
+ "mimo-v2-pro",
8169
+ "mimo-v2-omni",
8170
+ "mimo-v2-flash"
8171
+ ];
8172
+ var MIMO_TOKEN_PLAN_PREFERRED_MODELS = MIMO_PREFERRED_MODELS;
8103
8173
  var ProviderModelFetchError = class extends Error {
8104
8174
  constructor(message) {
8105
8175
  super(message);
@@ -8154,7 +8224,9 @@ function chooseRecommendedModel(provider, models, currentModel) {
8154
8224
  anthropic: ANTHROPIC_PREFERRED_MODELS,
8155
8225
  grok: GROK_PREFERRED_MODELS,
8156
8226
  ollamaCloud: OLLAMA_CLOUD_PREFERRED_MODELS,
8157
- ollamaLocal: OLLAMA_LOCAL_PREFERRED_MODELS
8227
+ ollamaLocal: OLLAMA_LOCAL_PREFERRED_MODELS,
8228
+ mimo: MIMO_PREFERRED_MODELS,
8229
+ mimoTokenPlan: MIMO_TOKEN_PLAN_PREFERRED_MODELS
8158
8230
  };
8159
8231
  for (const candidate of preferredByProvider[provider]) {
8160
8232
  if (models.includes(candidate)) {
@@ -8178,7 +8250,9 @@ function buildModelCatalog(provider, models, currentModel) {
8178
8250
  anthropic: ANTHROPIC_PREFERRED_MODELS,
8179
8251
  grok: GROK_PREFERRED_MODELS,
8180
8252
  ollamaCloud: OLLAMA_CLOUD_PREFERRED_MODELS,
8181
- ollamaLocal: OLLAMA_LOCAL_PREFERRED_MODELS
8253
+ ollamaLocal: OLLAMA_LOCAL_PREFERRED_MODELS,
8254
+ mimo: MIMO_PREFERRED_MODELS,
8255
+ mimoTokenPlan: MIMO_TOKEN_PLAN_PREFERRED_MODELS
8182
8256
  };
8183
8257
  const withoutRecommended = filtered.filter((model) => model !== recommendedModel);
8184
8258
  const prioritized = prioritizeModels(withoutRecommended, preferredByProvider[provider]);
@@ -8232,17 +8306,59 @@ async function fetchGrokModels(config) {
8232
8306
  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-"));
8233
8307
  return buildModelCatalog("grok", ids, config.model);
8234
8308
  }
8235
- async function fetchOllamaModels(provider, config) {
8236
- const headers = config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : void 0;
8309
+ async function fetchOllamaCloudModels(config) {
8237
8310
  const data = await fetchJson(
8238
- `${trimTrailingSlash(config.baseUrl)}/tags`,
8311
+ `${trimTrailingSlash(config.baseUrl)}/models`,
8239
8312
  {
8240
- headers
8313
+ headers: {
8314
+ Authorization: `Bearer ${config.apiKey}`
8315
+ }
8241
8316
  },
8242
- provider === "ollamaCloud" ? "Mercury could not fetch models for this Ollama Cloud key. Please re-enter it." : "Mercury could not fetch models from this Ollama Local server. Please check the base URL and try again."
8317
+ "Mercury could not fetch models for this Ollama Cloud key. Please re-enter it."
8318
+ );
8319
+ const ids = (data.data ?? []).map((model) => model.id?.trim() ?? "").filter(Boolean);
8320
+ return buildModelCatalog("ollamaCloud", ids, config.model);
8321
+ }
8322
+ async function fetchOllamaLocalModels(config) {
8323
+ const data = await fetchJson(
8324
+ `${trimTrailingSlash(config.baseUrl)}/tags`,
8325
+ {},
8326
+ "Mercury could not fetch models from this Ollama Local server. Please check the base URL and try again."
8243
8327
  );
8244
8328
  const ids = (data.models ?? []).map((model) => model.model?.trim() || model.name?.trim() || "").filter(Boolean);
8245
- return buildModelCatalog(provider, ids, config.model);
8329
+ return buildModelCatalog("ollamaLocal", ids, config.model);
8330
+ }
8331
+ async function fetchMiMoModels(config) {
8332
+ const data = await fetchJson(
8333
+ `${trimTrailingSlash(config.baseUrl)}/models`,
8334
+ {
8335
+ headers: {
8336
+ Authorization: `Bearer ${config.apiKey}`
8337
+ }
8338
+ },
8339
+ "Mercury could not fetch models for this MiMo key. Please re-enter it."
8340
+ );
8341
+ const ids = (data.data ?? []).map((model) => model.id?.trim() ?? "").filter((id) => {
8342
+ const lower = id.toLowerCase();
8343
+ return lower.startsWith("mimo-") && !lower.includes("tts");
8344
+ });
8345
+ return buildModelCatalog("mimo", ids, config.model);
8346
+ }
8347
+ async function fetchMiMoTokenPlanModels(config) {
8348
+ const data = await fetchJson(
8349
+ `${trimTrailingSlash(config.baseUrl)}/models`,
8350
+ {
8351
+ headers: {
8352
+ Authorization: `Bearer ${config.apiKey}`
8353
+ }
8354
+ },
8355
+ "Mercury could not fetch models for this MiMo Token Plan key. Please re-enter it."
8356
+ );
8357
+ const ids = (data.data ?? []).map((model) => model.id?.trim() ?? "").filter((id) => {
8358
+ const lower = id.toLowerCase();
8359
+ return lower.startsWith("mimo-") && !lower.includes("tts");
8360
+ });
8361
+ return buildModelCatalog("mimoTokenPlan", ids, config.model);
8246
8362
  }
8247
8363
  async function fetchProviderModelCatalog(provider, config) {
8248
8364
  if (provider === "anthropic") {
@@ -8251,8 +8367,17 @@ async function fetchProviderModelCatalog(provider, config) {
8251
8367
  if (provider === "grok") {
8252
8368
  return fetchGrokModels(config);
8253
8369
  }
8254
- if (provider === "ollamaCloud" || provider === "ollamaLocal") {
8255
- return fetchOllamaModels(provider, config);
8370
+ if (provider === "ollamaCloud") {
8371
+ return fetchOllamaCloudModels(config);
8372
+ }
8373
+ if (provider === "ollamaLocal") {
8374
+ return fetchOllamaLocalModels(config);
8375
+ }
8376
+ if (provider === "mimo") {
8377
+ return fetchMiMoModels(config);
8378
+ }
8379
+ if (provider === "mimoTokenPlan") {
8380
+ return fetchMiMoTokenPlanModels(config);
8256
8381
  }
8257
8382
  return fetchOpenAICompatModels(provider, config);
8258
8383
  }
@@ -8311,7 +8436,9 @@ var PROVIDER_OPTIONS = [
8311
8436
  { key: "anthropic", label: "Anthropic" },
8312
8437
  { key: "grok", label: "Grok (xAI)" },
8313
8438
  { key: "ollamaCloud", label: "Ollama Cloud" },
8314
- { key: "ollamaLocal", label: "Ollama Local" }
8439
+ { key: "ollamaLocal", label: "Ollama Local" },
8440
+ { key: "mimo", label: "MiMo (Xiaomi)" },
8441
+ { key: "mimoTokenPlan", label: "MiMo Token Plan (Xiaomi)" }
8315
8442
  ];
8316
8443
  function getConfiguredProviderNames(config) {
8317
8444
  return PROVIDER_OPTIONS.map((option) => option.key).filter((key) => isProviderConfigured(config.providers[key]));
@@ -8412,6 +8539,12 @@ function validateApiKey(provider, value) {
8412
8539
  if (provider === "ollamaCloud") {
8413
8540
  return looksLikeToken(value) ? null : "Ollama Cloud keys must look like a real API token: long, no spaces, and not plain text.";
8414
8541
  }
8542
+ if (provider === "mimo") {
8543
+ return /^sk-[A-Za-z0-9_-]{16,}$/i.test(value) ? null : "MiMo keys must start with `sk-`.";
8544
+ }
8545
+ if (provider === "mimoTokenPlan") {
8546
+ return /^tp-[A-Za-z0-9_-]{16,}$/i.test(value) ? null : "MiMo Token Plan keys must start with `tp-`.";
8547
+ }
8415
8548
  return null;
8416
8549
  }
8417
8550
  function validateBaseUrl(value) {
@@ -8760,6 +8893,38 @@ async function configure(existingConfig) {
8760
8893
  config.providers.ollamaLocal.model = result.model;
8761
8894
  config.providers.ollamaLocal.enabled = true;
8762
8895
  }
8896
+ continue;
8897
+ }
8898
+ if (provider === "mimo") {
8899
+ const mask = isReconfig && config.providers.mimo.apiKey ? ` [${maskKey(config.providers.mimo.apiKey)}]` : "";
8900
+ const result = await promptApiKeyWithModelSelection(
8901
+ config,
8902
+ "mimo",
8903
+ "MiMo",
8904
+ chalk7.white(` MiMo API key${mask}${isReconfig ? "" : " (Enter to skip)"}: `),
8905
+ isReconfig
8906
+ );
8907
+ if (!result.skipped && result.apiKey && result.model) {
8908
+ config.providers.mimo.apiKey = result.apiKey;
8909
+ config.providers.mimo.model = result.model;
8910
+ config.providers.mimo.enabled = true;
8911
+ }
8912
+ continue;
8913
+ }
8914
+ if (provider === "mimoTokenPlan") {
8915
+ const mask = isReconfig && config.providers.mimoTokenPlan.apiKey ? ` [${maskKey(config.providers.mimoTokenPlan.apiKey)}]` : "";
8916
+ const result = await promptApiKeyWithModelSelection(
8917
+ config,
8918
+ "mimoTokenPlan",
8919
+ "MiMo Token Plan",
8920
+ chalk7.white(` MiMo Token Plan API key${mask}${isReconfig ? "" : " (Enter to skip)"}: `),
8921
+ isReconfig
8922
+ );
8923
+ if (!result.skipped && result.apiKey && result.model) {
8924
+ config.providers.mimoTokenPlan.apiKey = result.apiKey;
8925
+ config.providers.mimoTokenPlan.model = result.model;
8926
+ config.providers.mimoTokenPlan.enabled = true;
8927
+ }
8763
8928
  }
8764
8929
  }
8765
8930
  const configuredProviders = getConfiguredProviderNames(config);