@iola_adm/iola-cli 0.1.47 → 0.1.49
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 +1 -1
- package/src/cli.js +63 -6
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -644,6 +644,20 @@ 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
|
+
const shouldSwitch = await confirm(`Активный AI-профиль ${readiness.activeProfile} (${readiness.activeProvider}) недоступен, найден ${fallback.name} (${fallback.provider}). Переключить активный профиль на ${fallback.name}? [Y/n] `);
|
|
651
|
+
if (shouldSwitch) {
|
|
652
|
+
await setActiveAiProfile(fallback.name, fallback);
|
|
653
|
+
console.log(`Активный AI-профиль: ${fallback.name} (${fallback.provider}, ${fallback.model || "-"})`);
|
|
654
|
+
} else {
|
|
655
|
+
console.log(`Для текстовых запросов будет использован доступный профиль ${fallback.name} (${fallback.provider}).`);
|
|
656
|
+
}
|
|
657
|
+
return readiness;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
647
661
|
if (!input.isTTY || !output.isTTY) {
|
|
648
662
|
console.log("AI-провайдер не настроен. Для настройки запустите: iola wizard");
|
|
649
663
|
return readiness;
|
|
@@ -696,6 +710,7 @@ async function getAiReadiness() {
|
|
|
696
710
|
activeProvider: activeProfile.provider || "-",
|
|
697
711
|
activeModel: activeProfile.model || "-",
|
|
698
712
|
anyReady: Boolean(ollama || openai || openrouter || codex),
|
|
713
|
+
profiles: config.ai.profiles || {},
|
|
699
714
|
ollama,
|
|
700
715
|
openai,
|
|
701
716
|
openrouter,
|
|
@@ -703,6 +718,16 @@ async function getAiReadiness() {
|
|
|
703
718
|
};
|
|
704
719
|
}
|
|
705
720
|
|
|
721
|
+
function getFallbackAiProfile(readiness) {
|
|
722
|
+
const priority = ["openai", "openrouter", "codex", "ollama"];
|
|
723
|
+
for (const provider of priority) {
|
|
724
|
+
if (!readiness[provider]) continue;
|
|
725
|
+
const entry = Object.entries(readiness.profiles || {}).find(([, profile]) => profile.provider === provider);
|
|
726
|
+
if (entry) return { name: entry[0], ...entry[1] };
|
|
727
|
+
}
|
|
728
|
+
return null;
|
|
729
|
+
}
|
|
730
|
+
|
|
706
731
|
async function hasUsableOllamaModel() {
|
|
707
732
|
try {
|
|
708
733
|
const config = await loadConfig();
|
|
@@ -725,7 +750,7 @@ async function hasUsableCodexAuth() {
|
|
|
725
750
|
}
|
|
726
751
|
|
|
727
752
|
async function startAgentReadline() {
|
|
728
|
-
const rl = readline.createInterface({ input, output, prompt: "
|
|
753
|
+
const rl = readline.createInterface({ input, output, prompt: "> " });
|
|
729
754
|
const state = {
|
|
730
755
|
history: [],
|
|
731
756
|
};
|
|
@@ -816,7 +841,7 @@ async function startAgentRawInput() {
|
|
|
816
841
|
render();
|
|
817
842
|
continue;
|
|
818
843
|
}
|
|
819
|
-
output.write(
|
|
844
|
+
output.write(`> ${line}\n`);
|
|
820
845
|
try {
|
|
821
846
|
const shouldExit = await handleAgentLine(line, state);
|
|
822
847
|
if (shouldExit) break;
|
|
@@ -1266,7 +1291,7 @@ function currentSlashMatches(state) {
|
|
|
1266
1291
|
|
|
1267
1292
|
function renderAgentInput(state) {
|
|
1268
1293
|
clearAgentInputArea(state);
|
|
1269
|
-
const prompt = "
|
|
1294
|
+
const prompt = "> ";
|
|
1270
1295
|
const lines = state.buffer.split("\n");
|
|
1271
1296
|
const inputLines = [`${prompt}${lines[0] || ""}`, ...lines.slice(1).map((line) => ` ${line}`)];
|
|
1272
1297
|
const cwdLine = colorMuted(` ${process.cwd()}`);
|
|
@@ -4365,6 +4390,13 @@ async function useAiProfile(name) {
|
|
|
4365
4390
|
throw new Error(`AI-профиль не найден: ${name}`);
|
|
4366
4391
|
}
|
|
4367
4392
|
|
|
4393
|
+
await setActiveAiProfile(name, profile, config);
|
|
4394
|
+
|
|
4395
|
+
console.log(`Активный AI-профиль: ${name} (${profile.provider}, ${profile.model || "-"})`);
|
|
4396
|
+
}
|
|
4397
|
+
|
|
4398
|
+
async function setActiveAiProfile(name, profile, loadedConfig = null) {
|
|
4399
|
+
const config = loadedConfig || await loadConfig();
|
|
4368
4400
|
await saveConfig({
|
|
4369
4401
|
ai: {
|
|
4370
4402
|
...config.ai,
|
|
@@ -4374,8 +4406,6 @@ async function useAiProfile(name) {
|
|
|
4374
4406
|
baseUrl: profile.baseUrl || config.ai.baseUrl,
|
|
4375
4407
|
},
|
|
4376
4408
|
});
|
|
4377
|
-
|
|
4378
|
-
console.log(`Активный AI-профиль: ${name} (${profile.provider}, ${profile.model || "-"})`);
|
|
4379
4409
|
}
|
|
4380
4410
|
|
|
4381
4411
|
async function deleteAiProfile(name) {
|
|
@@ -5866,7 +5896,7 @@ async function aiAsk(args, context = {}) {
|
|
|
5866
5896
|
}
|
|
5867
5897
|
|
|
5868
5898
|
const config = await loadConfig();
|
|
5869
|
-
const providerConfig =
|
|
5899
|
+
const providerConfig = await resolveUsableAiProfile(config, options);
|
|
5870
5900
|
if (providerConfig.provider === "codex") await assertPermission("codex");
|
|
5871
5901
|
if (providerConfig.provider !== "ollama") await assertPermission("externalAi");
|
|
5872
5902
|
if (options["stream-json"]) options.events = true;
|
|
@@ -5928,6 +5958,33 @@ async function aiAsk(args, context = {}) {
|
|
|
5928
5958
|
return answer;
|
|
5929
5959
|
}
|
|
5930
5960
|
|
|
5961
|
+
async function resolveUsableAiProfile(config, options = {}) {
|
|
5962
|
+
const explicit = Boolean(options.profile || options.provider);
|
|
5963
|
+
const providerConfig = resolveAiProfile(config, options);
|
|
5964
|
+
if (explicit) return providerConfig;
|
|
5965
|
+
|
|
5966
|
+
const readiness = await getAiReadiness();
|
|
5967
|
+
if (isProviderReady(providerConfig.provider, readiness)) return providerConfig;
|
|
5968
|
+
|
|
5969
|
+
const fallback = getFallbackAiProfile(readiness);
|
|
5970
|
+
if (!fallback) return providerConfig;
|
|
5971
|
+
|
|
5972
|
+
if (!options.quiet) {
|
|
5973
|
+
console.log(`Активный AI-профиль ${providerConfig.name} (${providerConfig.provider}) недоступен. Использую ${fallback.name} (${fallback.provider}).`);
|
|
5974
|
+
}
|
|
5975
|
+
|
|
5976
|
+
return {
|
|
5977
|
+
name: fallback.name,
|
|
5978
|
+
...fallback,
|
|
5979
|
+
model: fallback.model || providerConfig.model,
|
|
5980
|
+
baseUrl: fallback.baseUrl || providerConfig.baseUrl,
|
|
5981
|
+
};
|
|
5982
|
+
}
|
|
5983
|
+
|
|
5984
|
+
function isProviderReady(provider, readiness) {
|
|
5985
|
+
return Boolean(readiness?.[provider]);
|
|
5986
|
+
}
|
|
5987
|
+
|
|
5931
5988
|
function resolveAiProfile(config, options = {}) {
|
|
5932
5989
|
const profileName = options.profile || (options.provider && config.ai.profiles?.[options.provider]
|
|
5933
5990
|
? options.provider
|