@iola_adm/iola-cli 0.1.102 → 0.1.104
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 +83 -9
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -6570,10 +6570,10 @@ function buildCasualDirectAnswer(question) {
|
|
|
6570
6570
|
].join("\n");
|
|
6571
6571
|
}
|
|
6572
6572
|
if (/^(привет|здравствуй|здравствуйте|добрый день|доброе утро|добрый вечер|hi|hello|hey)([!.?\s]+(как дела|как ты|что нового)[?.!\s]*)?$/iu.test(normalized)) {
|
|
6573
|
-
return "Привет.
|
|
6573
|
+
return "Привет.";
|
|
6574
6574
|
}
|
|
6575
6575
|
if (/^(как дела|как ты|что нового|ты тут|ты здесь)[?.!\s]*$/iu.test(normalized)) {
|
|
6576
|
-
return "Я на месте.
|
|
6576
|
+
return "Я на месте.";
|
|
6577
6577
|
}
|
|
6578
6578
|
if (/^(спасибо|благодарю)[!.?\s]*$/iu.test(normalized)) {
|
|
6579
6579
|
return "Пожалуйста.";
|
|
@@ -6622,12 +6622,12 @@ function buildPersonRoleDirectAnswer(question) {
|
|
|
6622
6622
|
|
|
6623
6623
|
function extractPersonNameTokens(question) {
|
|
6624
6624
|
const stopWords = new Set([
|
|
6625
|
-
"так", "а", "и", "или", "кто", "что", "какой", "какая", "какого", "какой-то", "это",
|
|
6625
|
+
"так", "а", "в", "во", "и", "или", "кто", "что", "какой", "какая", "какого", "каком", "какую", "какой-то", "это",
|
|
6626
6626
|
"директор", "директора", "директором", "руководитель", "руководителем", "заведующая", "заведующий",
|
|
6627
|
-
"школа", "школы", "школе", "сад", "сада", "детский", "детского", "гимназия", "лицей",
|
|
6627
|
+
"школа", "школы", "школе", "школу", "сад", "сада", "саду", "детсад", "детсаду", "детский", "детского", "детском", "гимназия", "лицей",
|
|
6628
6628
|
"является", "возглавляет", "найди", "покажи",
|
|
6629
6629
|
]);
|
|
6630
|
-
return [...String(question || "").toLocaleLowerCase("ru-RU").matchAll(/\p{L}{
|
|
6630
|
+
return [...String(question || "").toLocaleLowerCase("ru-RU").matchAll(/\p{L}{2,}/gu)]
|
|
6631
6631
|
.map((match) => match[0])
|
|
6632
6632
|
.filter((token) => !stopWords.has(token));
|
|
6633
6633
|
}
|
|
@@ -6784,26 +6784,36 @@ async function resolvePublicEntityField(args = {}) {
|
|
|
6784
6784
|
const endpoint = `${await getApiBaseUrl()}/resolve-entity-field`;
|
|
6785
6785
|
const requestedField = normalizeEntityField(args.field);
|
|
6786
6786
|
const layer = normalizeEntityLayer(args.layer);
|
|
6787
|
+
const strictQuestionNumber = extractEntityNumberFromQuestion(args.source_question, layer);
|
|
6787
6788
|
const payload = {
|
|
6788
6789
|
layer,
|
|
6789
|
-
entity_number: args.entity_number ?? args.number,
|
|
6790
|
+
entity_number: strictQuestionNumber || (args.entity_number ?? args.number),
|
|
6790
6791
|
entity_name: args.entity_name || args.name,
|
|
6791
6792
|
inn: args.inn,
|
|
6792
6793
|
field: requestedField,
|
|
6793
6794
|
must_refute_user_value: args.must_refute_user_value,
|
|
6794
6795
|
source_question: args.source_question,
|
|
6796
|
+
strict_entity_number: Boolean(strictQuestionNumber),
|
|
6795
6797
|
};
|
|
6796
6798
|
try {
|
|
6797
6799
|
const resolved = await postJson(endpoint, stripInternalResolveArgs(payload));
|
|
6800
|
+
const correctedByNumber = await correctResolvedEntityByQuestionNumber(resolved, payload);
|
|
6801
|
+
if (correctedByNumber) return correctedByNumber;
|
|
6798
6802
|
return await correctResolvedEntityByQuestionName(resolved, payload) || resolved;
|
|
6799
6803
|
} catch (error) {
|
|
6804
|
+
if (payload.strict_entity_number && isEntityNotFoundError(error)) throw error;
|
|
6805
|
+
if (isLocalEntityValidationError(error)) throw error;
|
|
6800
6806
|
const fallbackField = pickResolveFieldFallback(requestedField, error);
|
|
6801
6807
|
if (fallbackField && fallbackField !== requestedField) {
|
|
6802
6808
|
try {
|
|
6803
6809
|
const fallbackPayload = { ...payload, field: fallbackField };
|
|
6804
6810
|
const resolved = await postJson(endpoint, stripInternalResolveArgs(fallbackPayload));
|
|
6811
|
+
const correctedByNumber = await correctResolvedEntityByQuestionNumber(resolved, fallbackPayload);
|
|
6812
|
+
if (correctedByNumber) return correctedByNumber;
|
|
6805
6813
|
return await correctResolvedEntityByQuestionName(resolved, fallbackPayload) || resolved;
|
|
6806
6814
|
} catch (retryError) {
|
|
6815
|
+
if (payload.strict_entity_number && isEntityNotFoundError(retryError)) throw retryError;
|
|
6816
|
+
if (isLocalEntityValidationError(retryError)) throw retryError;
|
|
6807
6817
|
const resolvedBySearch = await resolvePublicEntityFieldViaSearch({ ...payload, field: fallbackField }, retryError);
|
|
6808
6818
|
if (resolvedBySearch) return resolvedBySearch;
|
|
6809
6819
|
throw retryError;
|
|
@@ -6819,6 +6829,7 @@ async function resolvePublicEntityFieldViaSearch(payload, originalError) {
|
|
|
6819
6829
|
const details = parseErrorJsonDetails(originalError);
|
|
6820
6830
|
if (details?.error !== "entity_not_found") return null;
|
|
6821
6831
|
if (payload.inn) return null;
|
|
6832
|
+
if (payload.strict_entity_number) return null;
|
|
6822
6833
|
const query = payload.entity_name || buildEntitySearchQuery(payload.layer, payload.entity_number);
|
|
6823
6834
|
if (!query) return null;
|
|
6824
6835
|
const candidates = await searchPublicEntities({ layer: payload.layer, query, limit: 10 });
|
|
@@ -6833,10 +6844,28 @@ async function resolvePublicEntityFieldViaSearch(payload, originalError) {
|
|
|
6833
6844
|
}
|
|
6834
6845
|
|
|
6835
6846
|
function stripInternalResolveArgs(payload) {
|
|
6836
|
-
const { source_question: _sourceQuestion, ...publicPayload } = payload || {};
|
|
6847
|
+
const { source_question: _sourceQuestion, strict_entity_number: _strictEntityNumber, ...publicPayload } = payload || {};
|
|
6837
6848
|
return publicPayload;
|
|
6838
6849
|
}
|
|
6839
6850
|
|
|
6851
|
+
async function correctResolvedEntityByQuestionNumber(resolved, payload) {
|
|
6852
|
+
if (!payload.strict_entity_number || !payload.entity_number) return null;
|
|
6853
|
+
const resolvedEntity = resolved?.entity || resolved || {};
|
|
6854
|
+
if (itemNameHasNumber(resolvedEntity, payload.entity_number)) return null;
|
|
6855
|
+
|
|
6856
|
+
const candidates = await searchPublicEntities({ layer: payload.layer, query: buildEntitySearchQuery(payload.layer, payload.entity_number), limit: 10 });
|
|
6857
|
+
const candidate = candidates.find((item) => itemNameHasNumber(item, payload.entity_number));
|
|
6858
|
+
if (!candidate?.inn) throw createEntityNotFoundError(payload, buildEntitySearchQuery(payload.layer, payload.entity_number));
|
|
6859
|
+
if (candidate.inn === resolvedEntity.inn) return null;
|
|
6860
|
+
|
|
6861
|
+
return postJson(`${await getApiBaseUrl()}/resolve-entity-field`, stripInternalResolveArgs({
|
|
6862
|
+
layer: payload.layer,
|
|
6863
|
+
inn: candidate.inn,
|
|
6864
|
+
field: payload.field,
|
|
6865
|
+
must_refute_user_value: payload.must_refute_user_value,
|
|
6866
|
+
}));
|
|
6867
|
+
}
|
|
6868
|
+
|
|
6840
6869
|
async function correctResolvedEntityByQuestionName(resolved, payload) {
|
|
6841
6870
|
const questionNameQuery = extractEntityNameQueryFromQuestion(payload.source_question, payload.layer);
|
|
6842
6871
|
if (!questionNameQuery) return null;
|
|
@@ -6845,7 +6874,8 @@ async function correctResolvedEntityByQuestionName(resolved, payload) {
|
|
|
6845
6874
|
|
|
6846
6875
|
const candidates = await searchPublicEntities({ layer: payload.layer, query: questionNameQuery, limit: 5 });
|
|
6847
6876
|
const candidate = pickNamedEntityCandidate(candidates, questionNameQuery);
|
|
6848
|
-
if (!candidate?.inn
|
|
6877
|
+
if (!candidate?.inn) throw createEntityNotFoundError(payload, questionNameQuery);
|
|
6878
|
+
if (candidate.inn === resolvedEntity.inn) return null;
|
|
6849
6879
|
|
|
6850
6880
|
return postJson(`${await getApiBaseUrl()}/resolve-entity-field`, stripInternalResolveArgs({
|
|
6851
6881
|
layer: payload.layer,
|
|
@@ -6857,6 +6887,7 @@ async function correctResolvedEntityByQuestionName(resolved, payload) {
|
|
|
6857
6887
|
|
|
6858
6888
|
function extractEntityNameQueryFromQuestion(question, layer) {
|
|
6859
6889
|
let text = String(question || "").toLocaleLowerCase("ru-RU");
|
|
6890
|
+
if (extractEntityNumberFromQuestion(text, layer)) return "";
|
|
6860
6891
|
const correction = text.match(/(?:просил|просила|просили)\s+(.+?)\s+а\s+не(?:\s|$)/iu);
|
|
6861
6892
|
if (correction?.[1]) text = correction[1];
|
|
6862
6893
|
|
|
@@ -6864,7 +6895,7 @@ function extractEntityNameQueryFromQuestion(question, layer) {
|
|
|
6864
6895
|
"а", "в", "во", "где", "же", "и", "или", "как", "какая", "какие", "какой", "кто", "на", "не",
|
|
6865
6896
|
"найди", "находится", "подскажи", "покажи", "просил", "скажи", "так", "там", "это",
|
|
6866
6897
|
"адрес", "директор", "директора", "заведующая", "заведующий", "инн", "почта", "сайт", "телефон",
|
|
6867
|
-
"гимназия", "детсад", "детсада", "детский", "лицей", "мбдоу", "мбоу", "сад", "сада", "садик",
|
|
6898
|
+
"гимназия", "гимназии", "детсад", "детсада", "детский", "лицей", "лицея", "лицее", "мбдоу", "мбоу", "сад", "сада", "садик",
|
|
6868
6899
|
"сош", "школа", "школе", "школу", "школы",
|
|
6869
6900
|
]);
|
|
6870
6901
|
const tokens = [...text.normalize("NFC").matchAll(/[\p{L}\d]+/gu)]
|
|
@@ -6904,6 +6935,38 @@ function normalizeEntityText(text) {
|
|
|
6904
6935
|
return String(text || "").toLocaleLowerCase("ru-RU").replace(/ё/g, "е");
|
|
6905
6936
|
}
|
|
6906
6937
|
|
|
6938
|
+
function extractEntityNumberFromQuestion(question, layer) {
|
|
6939
|
+
const text = String(question || "").toLocaleLowerCase("ru-RU");
|
|
6940
|
+
const isKindergarten = layer === "kindergartens";
|
|
6941
|
+
const isSchool = layer === "schools";
|
|
6942
|
+
const patterns = isKindergarten
|
|
6943
|
+
? [/(?:детск\w*\s+сад\w*|детсад\w*|сад\w*)\s*(?:№|номер|n)?\s*(\d{1,4})/iu, /№\s*(\d{1,4})/iu]
|
|
6944
|
+
: isSchool
|
|
6945
|
+
? [/(?:школ\w*|сош|гимнази\w*|лице\w*)\s*(?:№|номер|n)?\s*(\d{1,4})/iu, /№\s*(\d{1,4})/iu]
|
|
6946
|
+
: [/№\s*(\d{1,4})/iu];
|
|
6947
|
+
for (const pattern of patterns) {
|
|
6948
|
+
const match = text.match(pattern);
|
|
6949
|
+
if (match?.[1]) return match[1];
|
|
6950
|
+
}
|
|
6951
|
+
return "";
|
|
6952
|
+
}
|
|
6953
|
+
|
|
6954
|
+
function createEntityNotFoundError(payload, query = "") {
|
|
6955
|
+
const detail = {
|
|
6956
|
+
error: "entity_not_found",
|
|
6957
|
+
message: "No public entity matched the provided selector",
|
|
6958
|
+
layer: payload.layer,
|
|
6959
|
+
entity_number: payload.entity_number,
|
|
6960
|
+
entity_name: payload.entity_name || query,
|
|
6961
|
+
local_validation: true,
|
|
6962
|
+
};
|
|
6963
|
+
return new Error(`Request failed: 404 Not Found (${awaitedApiPlaceholder()})\n${JSON.stringify({ detail })}`);
|
|
6964
|
+
}
|
|
6965
|
+
|
|
6966
|
+
function awaitedApiPlaceholder() {
|
|
6967
|
+
return "local-validation";
|
|
6968
|
+
}
|
|
6969
|
+
|
|
6907
6970
|
function buildEntitySearchQuery(layer, number) {
|
|
6908
6971
|
if (number === undefined || number === null || number === "") return "";
|
|
6909
6972
|
const label = layer === "kindergartens" ? "детский сад" : "школа";
|
|
@@ -6964,9 +7027,20 @@ function parseErrorJsonDetails(error) {
|
|
|
6964
7027
|
}
|
|
6965
7028
|
}
|
|
6966
7029
|
|
|
7030
|
+
function isEntityNotFoundError(error) {
|
|
7031
|
+
return parseErrorJsonDetails(error)?.error === "entity_not_found";
|
|
7032
|
+
}
|
|
7033
|
+
|
|
7034
|
+
function isLocalEntityValidationError(error) {
|
|
7035
|
+
return Boolean(parseErrorJsonDetails(error)?.local_validation);
|
|
7036
|
+
}
|
|
7037
|
+
|
|
6967
7038
|
function formatToolExecutionError(error, plan) {
|
|
6968
7039
|
const details = parseErrorJsonDetails(error);
|
|
6969
7040
|
if (details?.error !== "entity_not_found") return "";
|
|
7041
|
+
if (details.local_validation && details.entity_name) {
|
|
7042
|
+
return `В открытом слое не нашел организацию по названию "${details.entity_name}". Проверьте название.`;
|
|
7043
|
+
}
|
|
6970
7044
|
|
|
6971
7045
|
const step = (plan?.steps || []).find((item) => item.tool === "resolve_entity_field" || item.tool === "search_entities");
|
|
6972
7046
|
const args = step?.args || {};
|