@iola_adm/iola-cli 0.1.70 → 0.1.72
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 +74 -8
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -766,7 +766,7 @@ async function startAgentReadline() {
|
|
|
766
766
|
}
|
|
767
767
|
|
|
768
768
|
async function startAgentRawInput() {
|
|
769
|
-
const state = { history: [], buffer: "", selected: 0, slashOffset: 0, slashOpen: false, running: false, renderedInputLines: 0, rawMode: true, pendingOutput: "", aiStatus: null };
|
|
769
|
+
const state = { history: [], buffer: "", selected: 0, slashOffset: 0, slashOpen: false, running: false, renderedInputLines: 0, renderedLines: 0, rawMode: true, pendingOutput: "", aiStatus: null };
|
|
770
770
|
const wasRaw = input.isRaw;
|
|
771
771
|
activateRawInput(input);
|
|
772
772
|
|
|
@@ -1330,14 +1330,18 @@ function renderAgentInput(state) {
|
|
|
1330
1330
|
output.write(`\x1b[${cursorColumn + 1}G`);
|
|
1331
1331
|
}
|
|
1332
1332
|
state.renderedInputLines = inputLines.length;
|
|
1333
|
+
state.renderedLines = renderedLines.length;
|
|
1333
1334
|
}
|
|
1334
1335
|
|
|
1335
1336
|
function clearAgentInputArea(state = null) {
|
|
1336
1337
|
if (!output.isTTY) return;
|
|
1337
|
-
const
|
|
1338
|
-
if (
|
|
1338
|
+
const renderedLines = Math.max(1, Number(state?.renderedLines || state?.renderedInputLines || 1));
|
|
1339
|
+
if (renderedLines > 1) output.write(`\x1b[${renderedLines - 1}A`);
|
|
1339
1340
|
output.write("\r\x1b[0J");
|
|
1340
|
-
if (state)
|
|
1341
|
+
if (state) {
|
|
1342
|
+
state.renderedInputLines = 0;
|
|
1343
|
+
state.renderedLines = 0;
|
|
1344
|
+
}
|
|
1341
1345
|
}
|
|
1342
1346
|
|
|
1343
1347
|
function startActivityIndicator(label = "работаю") {
|
|
@@ -5965,6 +5969,20 @@ async function aiAsk(args, context = {}) {
|
|
|
5965
5969
|
const historyEnabled = !options.bare && !options["no-history"] && isFeatureEnabled("sqlite-history");
|
|
5966
5970
|
const sessionId = historyEnabled && isFeatureEnabled("sessions") ? ensureSessionForAsk(options, providerConfig, question) : null;
|
|
5967
5971
|
const history = context.history || (sessionId ? getSessionAiHistory(sessionId) : []);
|
|
5972
|
+
const directAnswer = buildDirectDataAnswer(question, dataContext);
|
|
5973
|
+
if (directAnswer) {
|
|
5974
|
+
if (historyEnabled) {
|
|
5975
|
+
recordAskHistory({ question, answer: directAnswer, providerConfig, dataContext, error: "", sessionId });
|
|
5976
|
+
appendSessionExchange(sessionId, question, directAnswer, dataContext, "");
|
|
5977
|
+
}
|
|
5978
|
+
emitEvent(options, "answer", { length: directAnswer.length, sessionId, direct: true });
|
|
5979
|
+
if (options.output) {
|
|
5980
|
+
await assertPermission("writeFiles");
|
|
5981
|
+
await writeFile(options.output, directAnswer, "utf8");
|
|
5982
|
+
}
|
|
5983
|
+
if (!options.quiet) console.log(directAnswer);
|
|
5984
|
+
return directAnswer;
|
|
5985
|
+
}
|
|
5968
5986
|
const messages = await buildAiMessages(question, dataContext, history, options, config);
|
|
5969
5987
|
let answer = "";
|
|
5970
5988
|
let errorMessage = "";
|
|
@@ -6014,6 +6032,28 @@ async function aiAsk(args, context = {}) {
|
|
|
6014
6032
|
return answer;
|
|
6015
6033
|
}
|
|
6016
6034
|
|
|
6035
|
+
function buildDirectDataAnswer(question, dataContext) {
|
|
6036
|
+
const normalized = question.toLocaleLowerCase("ru-RU");
|
|
6037
|
+
if (!/(директор|руководител)/iu.test(normalized)) return "";
|
|
6038
|
+
const terms = extractSearchTerms(question).filter((term) => !/^\d+$/.test(term));
|
|
6039
|
+
if (terms.length < 2) return "";
|
|
6040
|
+
const rows = [
|
|
6041
|
+
...dataContext.schools.map((item) => ({ layer: "schools", layerName: "школы", ...item })),
|
|
6042
|
+
...dataContext.kindergartens.map((item) => ({ layer: "kindergartens", layerName: "детские сады", ...item })),
|
|
6043
|
+
];
|
|
6044
|
+
const matches = rows.filter((item) => {
|
|
6045
|
+
const head = String(item.head || "").toLocaleLowerCase("ru-RU");
|
|
6046
|
+
return terms.every((term) => head.includes(term));
|
|
6047
|
+
});
|
|
6048
|
+
if (matches.length !== 1) return "";
|
|
6049
|
+
const item = matches[0];
|
|
6050
|
+
return [
|
|
6051
|
+
`${item.head} — руководитель ${item.name}.`,
|
|
6052
|
+
item.address ? `Адрес: ${item.address}.` : "",
|
|
6053
|
+
`Источник: слой ${item.layer}, ИНН ${item.inn || "-"}.`,
|
|
6054
|
+
].filter(Boolean).join("\n");
|
|
6055
|
+
}
|
|
6056
|
+
|
|
6017
6057
|
async function resolveUsableAiProfile(config, options = {}) {
|
|
6018
6058
|
const explicit = Boolean(options.profile || options.provider);
|
|
6019
6059
|
const providerConfig = resolveAiProfile(config, options);
|
|
@@ -6431,8 +6471,8 @@ async function buildDataContext(question) {
|
|
|
6431
6471
|
const mcpBaseUrl = await getMcpBaseUrl();
|
|
6432
6472
|
const [layers, schools, kindergartens] = await Promise.all([
|
|
6433
6473
|
fetchJson(`${mcpBaseUrl}/mcp-version`),
|
|
6434
|
-
|
|
6435
|
-
|
|
6474
|
+
fetchAllApiItems(`${apiBaseUrl}/schools`),
|
|
6475
|
+
fetchAllApiItems(`${apiBaseUrl}/kindergartens`),
|
|
6436
6476
|
]);
|
|
6437
6477
|
const queryTerms = extractSearchTerms(question);
|
|
6438
6478
|
const patterns = extractStructuredPatterns(question);
|
|
@@ -6457,6 +6497,18 @@ async function buildDataContext(question) {
|
|
|
6457
6497
|
};
|
|
6458
6498
|
}
|
|
6459
6499
|
|
|
6500
|
+
async function fetchAllApiItems(endpoint, limit = 500, maxItems = 5000) {
|
|
6501
|
+
const all = [];
|
|
6502
|
+
for (let offset = 0; offset < maxItems; offset += limit) {
|
|
6503
|
+
const separator = endpoint.includes("?") ? "&" : "?";
|
|
6504
|
+
const payload = await fetchJson(`${endpoint}${separator}limit=${limit}&offset=${offset}`);
|
|
6505
|
+
const items = normalizeItems(payload);
|
|
6506
|
+
all.push(...items);
|
|
6507
|
+
if (items.length < limit) break;
|
|
6508
|
+
}
|
|
6509
|
+
return all;
|
|
6510
|
+
}
|
|
6511
|
+
|
|
6460
6512
|
function emptyDataContext(question) {
|
|
6461
6513
|
return {
|
|
6462
6514
|
enabled: false,
|
|
@@ -6477,7 +6529,13 @@ function shouldUseDataContext(question, options = {}) {
|
|
|
6477
6529
|
if (/^(привет|здравствуй|здравствуйте|добрый день|доброе утро|добрый вечер|hi|hello|hey)[!.?\s]*$/iu.test(normalized)) return false;
|
|
6478
6530
|
if (/^(спасибо|благодарю|ок|окей|понял|поняла|ясно|хорошо|да|нет)[!.?\s]*$/iu.test(normalized)) return false;
|
|
6479
6531
|
if (normalized.length <= 24 && /^(как дела|что нового|ты тут|ты здесь|кто ты)[?.!\s]*$/iu.test(normalized)) return false;
|
|
6480
|
-
|
|
6532
|
+
const dataKeywords = [
|
|
6533
|
+
"школ", "сад", "детсад", "детский сад", "лицей", "гимнази", "инн", "адрес", "телефон",
|
|
6534
|
+
"почт", "email", "сайт", "лиценз", "руководител", "директор", "слой", "слои", "данн",
|
|
6535
|
+
"отчет", "отчёт", "выгруз", "csv", "json", "найди", "покажи", "список", "карточк",
|
|
6536
|
+
"организац", "учрежден", "йошкар", "ола", "петрова", "строител", "советск", "первомайск",
|
|
6537
|
+
];
|
|
6538
|
+
return dataKeywords.some((keyword) => normalized.includes(keyword));
|
|
6481
6539
|
}
|
|
6482
6540
|
|
|
6483
6541
|
function extractSearchTerms(question) {
|
|
@@ -6487,7 +6545,13 @@ function extractSearchTerms(question) {
|
|
|
6487
6545
|
.split(/\s+/)
|
|
6488
6546
|
.map((term) => term.trim())
|
|
6489
6547
|
.filter(Boolean)
|
|
6490
|
-
.filter((term) => ![
|
|
6548
|
+
.filter((term) => ![
|
|
6549
|
+
"в", "во", "на", "по", "и", "а", "ну", "так", "слушай", "скажи", "подскажи",
|
|
6550
|
+
"какие", "какая", "какой", "каком", "какой", "есть", "найди", "покажи",
|
|
6551
|
+
"контакты", "адрес", "телефон", "школы", "школа", "школе", "сад", "детский",
|
|
6552
|
+
"детские", "сады", "улица", "ул", "директор", "руководитель",
|
|
6553
|
+
].includes(term))
|
|
6554
|
+
.filter((term) => term.length > 2 || /^\d+$/.test(term));
|
|
6491
6555
|
|
|
6492
6556
|
return normalized.length > 0 ? normalized : [question];
|
|
6493
6557
|
}
|
|
@@ -6535,8 +6599,10 @@ function scoreItem(item, terms, patterns, layer) {
|
|
|
6535
6599
|
const text = JSON.stringify(summary).toLocaleLowerCase("ru-RU");
|
|
6536
6600
|
const name = String(summary.name || "").toLocaleLowerCase("ru-RU");
|
|
6537
6601
|
const address = String(summary.address || "").toLocaleLowerCase("ru-RU");
|
|
6602
|
+
const head = String(summary.head || "").toLocaleLowerCase("ru-RU");
|
|
6538
6603
|
const generalTerms = terms.filter((term) => !/^\d+$/.test(term));
|
|
6539
6604
|
let score = generalTerms.reduce((value, term) => value + (text.includes(term.toLocaleLowerCase("ru-RU")) ? 1 : 0), 0);
|
|
6605
|
+
score += generalTerms.reduce((value, term) => value + (head.includes(term.toLocaleLowerCase("ru-RU")) ? 5 : 0), 0);
|
|
6540
6606
|
|
|
6541
6607
|
for (const inn of patterns.inns) {
|
|
6542
6608
|
if (String(summary.inn) === inn) {
|