@iola_adm/iola-cli 0.1.94 → 0.1.96

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 +49 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iola_adm/iola-cli",
3
- "version": "0.1.94",
3
+ "version": "0.1.96",
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
@@ -33,7 +33,7 @@ const LOCAL_CONFIG_FILE = path.join(PROJECT_IOLA_DIR, "local.json");
33
33
  const BROWSER_RUNTIME_DIR = path.join(CONFIG_DIR, "browser-runtime");
34
34
  const BROWSER_RUNTIME_PACKAGE = path.join(BROWSER_RUNTIME_DIR, "node_modules", "playwright", "package.json");
35
35
  const INDEXABLE_EXTENSIONS = /\.(md|txt|csv|json|html|docx|xlsx|pptx|pdf)$/i;
36
- const LOCAL_TOOLS = ["search_data", "search_entities", "resolve_entity_field", "get_card", "export_report", "file_read", "browser_open"];
36
+ const LOCAL_TOOLS = ["search_data", "search_entities", "resolve_entity_field", "get_card", "export_report", "file_read", "browser_open", "get_current_date"];
37
37
  const LEGACY_LOCAL_TOOLS = ["search_local", "export_data", "run_report", "save_view"];
38
38
  const FILE_TOOLS = ["files_tree", "files_read", "files_search", "files_write", "files_patch"];
39
39
  const ALL_LOCAL_TOOLS = [...LOCAL_TOOLS, ...FILE_TOOLS];
@@ -6436,6 +6436,11 @@ async function localToolAsk(question, providerConfig, options) {
6436
6436
  if (!options.quiet) console.log(guarded);
6437
6437
  return guarded;
6438
6438
  }
6439
+ const casualAnswer = buildCasualDirectAnswer(question);
6440
+ if (casualAnswer) {
6441
+ if (!options.quiet) console.log(casualAnswer);
6442
+ return casualAnswer;
6443
+ }
6439
6444
  await ensureLocalData();
6440
6445
  const plan = await buildLocalToolPlan(question, providerConfig, options);
6441
6446
  if (plan.directAnswer) {
@@ -6489,6 +6494,23 @@ function guardNonPublicQuestion(question) {
6489
6494
  return "";
6490
6495
  }
6491
6496
 
6497
+ function buildCasualDirectAnswer(question) {
6498
+ const normalized = String(question || "").toLocaleLowerCase("ru-RU").trim();
6499
+ if (/^(кто ты|что ты|какая ты модель|что ты за модель|что за модель|какая модель|назови модель|ты какая модель|ты кто)([?.!\s]*)$/iu.test(normalized)) {
6500
+ return "Я IOLA, первая городская модель искусственного интеллекта Йошкар-Олы. Работаю локально в CLI и отвечаю по открытым городским данным через проверяемые слои и API.";
6501
+ }
6502
+ if (/^(привет|здравствуй|здравствуйте|добрый день|доброе утро|добрый вечер|hi|hello|hey)([!.?\s]+(как дела|как ты|что нового)[?.!\s]*)?$/iu.test(normalized)) {
6503
+ return "Привет. Работаю нормально. Могу помочь с открытыми данными Йошкар-Олы: школами, детскими садами, адресами, телефонами, сайтами и ИНН.";
6504
+ }
6505
+ if (/^(как дела|как ты|что нового|ты тут|ты здесь)[?.!\s]*$/iu.test(normalized)) {
6506
+ return "Я на месте. Могу искать и проверять открытые городские данные.";
6507
+ }
6508
+ if (/^(спасибо|благодарю)[!.?\s]*$/iu.test(normalized)) {
6509
+ return "Пожалуйста.";
6510
+ }
6511
+ return "";
6512
+ }
6513
+
6492
6514
  function printToolPlan(plan) {
6493
6515
  console.log("План выполнения:");
6494
6516
  plan.steps.forEach((step, index) => {
@@ -6534,7 +6556,12 @@ async function buildLocalToolPlan(question, providerConfig, options) {
6534
6556
  function normalizeIolaRouterPlan(raw, question, options = {}) {
6535
6557
  const payload = typeof raw === "string" ? parseJsonObject(raw) : raw;
6536
6558
  if (payload.action === "tool_call") {
6537
- const tool = payload.tool === "get_entity_field" ? "resolve_entity_field" : payload.tool;
6559
+ const tool = normalizeIolaToolName(payload.tool);
6560
+ if (!availableToolNames(options).includes(tool)) {
6561
+ const casualAnswer = buildCasualDirectAnswer(question);
6562
+ if (casualAnswer) return { directAnswer: casualAnswer };
6563
+ return inferToolPlan(question, options);
6564
+ }
6538
6565
  return { steps: [{ tool, args: payload.args || {} }] };
6539
6566
  }
6540
6567
  if (payload.action === "direct_answer") {
@@ -6552,6 +6579,12 @@ function normalizeIolaRouterPlan(raw, question, options = {}) {
6552
6579
  throw new Error(`IOLA router вернул неподдерживаемое действие: ${payload.action || "unknown"}`);
6553
6580
  }
6554
6581
 
6582
+ function normalizeIolaToolName(tool) {
6583
+ if (tool === "get_entity_field") return "resolve_entity_field";
6584
+ if (tool === "current_date" || tool === "date_now" || tool === "today") return "get_current_date";
6585
+ return tool;
6586
+ }
6587
+
6555
6588
  function parseJsonObject(text) {
6556
6589
  const match = String(text).match(/\{[\s\S]*\}/);
6557
6590
  if (!match) throw new Error("JSON-план не найден.");
@@ -6704,6 +6737,9 @@ async function executeToolPlan(plan, options = {}) {
6704
6737
  const text = await runBrowserAutomation("text", { url: step.args?.url, waitMs: Number(step.args?.waitMs || 0), timeout: Number(step.args?.timeout || 30000), viewport: step.args?.viewport || "1366x768" });
6705
6738
  current = [{ url: step.args?.url, text }];
6706
6739
  outputs.push({ tool: step.tool, rows: 1 });
6740
+ } else if (step.tool === "get_current_date") {
6741
+ current = [getCurrentDateInfo()];
6742
+ outputs.push({ tool: step.tool, rows: current.length });
6707
6743
  } else if (String(step.tool || "").startsWith("mcp:")) {
6708
6744
  const result = await callConfiguredMcpTool(step.tool, step.args || {});
6709
6745
  current = Array.isArray(result) ? result : [result];
@@ -6742,6 +6778,16 @@ async function executeToolPlan(plan, options = {}) {
6742
6778
  return { rows: current, outputs };
6743
6779
  }
6744
6780
 
6781
+ function getCurrentDateInfo() {
6782
+ const now = new Date();
6783
+ return {
6784
+ name: "текущая дата",
6785
+ date: new Intl.DateTimeFormat("ru-RU", { dateStyle: "long" }).format(now),
6786
+ time: new Intl.DateTimeFormat("ru-RU", { timeStyle: "short" }).format(now),
6787
+ iso: now.toISOString(),
6788
+ };
6789
+ }
6790
+
6745
6791
  function getLocalMcpToolNames() {
6746
6792
  return mcpTools().map((tool) => `mcp:iola-local:${tool.name}`);
6747
6793
  }
@@ -6824,6 +6870,7 @@ function formatToolResult(result, options) {
6824
6870
  const name = row.entity.name || row.entity.inn || "организация";
6825
6871
  return `${name}: ${row.field} = ${row.value ?? "не указано"}`;
6826
6872
  }
6873
+ if (row.date && row.time) return `Сегодня ${row.date}, ${row.time}.`;
6827
6874
  return `${row.name || row.check || row.inn || "строка"}: ${row.address || row.phone || row.email || row.website || row.count || ""}`;
6828
6875
  }).join("\n");
6829
6876
  }