@iola_adm/iola-cli 0.1.47 → 0.1.48

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/cli.js +47 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iola_adm/iola-cli",
3
- "version": "0.1.47",
3
+ "version": "0.1.48",
4
4
  "description": "CLI и AI-агент городского округа Йошкар-Ола.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/adm-iola/iola-cli#readme",
package/src/cli.js CHANGED
@@ -644,6 +644,14 @@ async function ensureAgentAiReady() {
644
644
  const readiness = await getAiReadiness();
645
645
  if (readiness.ready) return readiness;
646
646
 
647
+ if (readiness.anyReady) {
648
+ const fallback = getFallbackAiProfile(readiness);
649
+ if (fallback) {
650
+ console.log(`Активный AI-профиль ${readiness.activeProfile} (${readiness.activeProvider}) недоступен. Для текстовых запросов будет использован доступный профиль ${fallback.name} (${fallback.provider}).`);
651
+ return readiness;
652
+ }
653
+ }
654
+
647
655
  if (!input.isTTY || !output.isTTY) {
648
656
  console.log("AI-провайдер не настроен. Для настройки запустите: iola wizard");
649
657
  return readiness;
@@ -696,6 +704,7 @@ async function getAiReadiness() {
696
704
  activeProvider: activeProfile.provider || "-",
697
705
  activeModel: activeProfile.model || "-",
698
706
  anyReady: Boolean(ollama || openai || openrouter || codex),
707
+ profiles: config.ai.profiles || {},
699
708
  ollama,
700
709
  openai,
701
710
  openrouter,
@@ -703,6 +712,16 @@ async function getAiReadiness() {
703
712
  };
704
713
  }
705
714
 
715
+ function getFallbackAiProfile(readiness) {
716
+ const priority = ["openai", "openrouter", "codex", "ollama"];
717
+ for (const provider of priority) {
718
+ if (!readiness[provider]) continue;
719
+ const entry = Object.entries(readiness.profiles || {}).find(([, profile]) => profile.provider === provider);
720
+ if (entry) return { name: entry[0], ...entry[1] };
721
+ }
722
+ return null;
723
+ }
724
+
706
725
  async function hasUsableOllamaModel() {
707
726
  try {
708
727
  const config = await loadConfig();
@@ -5866,7 +5885,7 @@ async function aiAsk(args, context = {}) {
5866
5885
  }
5867
5886
 
5868
5887
  const config = await loadConfig();
5869
- const providerConfig = resolveAiProfile(config, options);
5888
+ const providerConfig = await resolveUsableAiProfile(config, options);
5870
5889
  if (providerConfig.provider === "codex") await assertPermission("codex");
5871
5890
  if (providerConfig.provider !== "ollama") await assertPermission("externalAi");
5872
5891
  if (options["stream-json"]) options.events = true;
@@ -5928,6 +5947,33 @@ async function aiAsk(args, context = {}) {
5928
5947
  return answer;
5929
5948
  }
5930
5949
 
5950
+ async function resolveUsableAiProfile(config, options = {}) {
5951
+ const explicit = Boolean(options.profile || options.provider);
5952
+ const providerConfig = resolveAiProfile(config, options);
5953
+ if (explicit) return providerConfig;
5954
+
5955
+ const readiness = await getAiReadiness();
5956
+ if (isProviderReady(providerConfig.provider, readiness)) return providerConfig;
5957
+
5958
+ const fallback = getFallbackAiProfile(readiness);
5959
+ if (!fallback) return providerConfig;
5960
+
5961
+ if (!options.quiet) {
5962
+ console.log(`Активный AI-профиль ${providerConfig.name} (${providerConfig.provider}) недоступен. Использую ${fallback.name} (${fallback.provider}).`);
5963
+ }
5964
+
5965
+ return {
5966
+ name: fallback.name,
5967
+ ...fallback,
5968
+ model: fallback.model || providerConfig.model,
5969
+ baseUrl: fallback.baseUrl || providerConfig.baseUrl,
5970
+ };
5971
+ }
5972
+
5973
+ function isProviderReady(provider, readiness) {
5974
+ return Boolean(readiness?.[provider]);
5975
+ }
5976
+
5931
5977
  function resolveAiProfile(config, options = {}) {
5932
5978
  const profileName = options.profile || (options.provider && config.ai.profiles?.[options.provider]
5933
5979
  ? options.provider