answer42 0.4.76__tar.gz → 0.4.78__tar.gz
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.
- {answer42-0.4.76 → answer42-0.4.78}/PKG-INFO +1 -1
- {answer42-0.4.76 → answer42-0.4.78}/pyproject.toml +1 -1
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/assets/skills/answer42-rag/SKILL.md +1 -1
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/server.py +215 -47
- {answer42-0.4.76 → answer42-0.4.78}/.gitignore +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/LICENSE +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/README.md +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/credentials.example.json +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/docs/agent-installation.md +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/docs/architecture.md +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/docs/assets/answer42-logo.png +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/docs/assets/platform42-logo.svg +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/docs/installation.md +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/scripts/build_cf.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/scripts/build_pages.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/scripts/e2e_http_smoke.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/scripts/e2e_stable.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/scripts/openclaw_mcp_autoreload.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/scripts/rag_cli.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/cf/ConfigDumpInfo.xml +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/cf/Configuration.xml +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/cf/DataProcessors/MCPTestManager/Ext/ObjectModule.bsl +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260/Ext/Form/Module.bsl" +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260/Ext/Form.xml" +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260.xml" +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/cf/DataProcessors/MCPTestManager.xml +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/cf/Ext/ManagedApplicationModule.bsl +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/cf/Languages//320/240/321/203/321/201/321/201/320/272/320/270/320/271.xml" +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/client_cf/Catalogs//320/237/320/241_/320/222/320/273/320/260/320/264/320/265/320/273/320/265/321/206.xml" +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/client_cf/Catalogs//320/237/320/241_/320/241/320/277/321/200/320/260/320/262/320/276/321/207/320/275/320/270/320/2721.xml" +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/client_cf/ConfigDumpInfo.xml +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/client_cf/Configuration.xml +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/client_cf/Languages//320/240/321/203/321/201/321/201/320/272/320/270/320/271.xml" +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Ext/ManagerModule.bsl" +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Ext/ObjectModule.bsl" +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Templates//320/236/321/201/320/275/320/276/320/262/320/275/320/260/321/217/320/241/321/205/320/265/320/274/320/260/320/232/320/276/320/274/320/277/320/276/320/275/320/276/320/262/320/272/320/270/320/224/320/260/320/275/320/275/321/213/321/205/Ext/Template.xml" +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Templates//320/236/321/201/320/275/320/276/320/262/320/275/320/260/321/217/320/241/321/205/320/265/320/274/320/260/320/232/320/276/320/274/320/277/320/276/320/275/320/276/320/262/320/272/320/270/320/224/320/260/320/275/320/275/321/213/321/205.xml" +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262.xml" +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/__init__.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/assets/MCPTestClient.cf +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/assets/MCPTestManager.cf +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/assets/__init__.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/assets/skills/answer42/SKILL.md +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/assets/skills/answer42-universal-report/SKILL.md +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/auth.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/bridge.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/credentials.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/os_support.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/platform.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/protocol.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/rag/__init__.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/rag/detect.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/rag/dump.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/rag/model.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/rag/parsers.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/rag/service.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/rag/store.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/rag/summary_backend.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/rag/summary_vector.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/recorder.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/release_helper.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/runtime.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/skill_installer.py +0 -0
- {answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/window_control.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: answer42
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.78
|
|
4
4
|
Summary: Answer42 — The Answer to Life, Universe, and 1C — UI Driver. MCP-powered 1C:Enterprise UI automation: click, fill, navigate, test, and introspect managed forms through the test-client API
|
|
5
5
|
Author: Marvin (AI Assistant), 42Clouds, and contributors
|
|
6
6
|
Author-email: "Kosolapov Stanislav (proDOOMman)" <prodoomman@gmail.com>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "answer42"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.78"
|
|
4
4
|
description = "Answer42 — The Answer to Life, Universe, and 1C — UI Driver. MCP-powered 1C:Enterprise UI automation: click, fill, navigate, test, and introspect managed forms through the test-client API"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -61,7 +61,7 @@ rag_session_autoconfigure()
|
|
|
61
61
|
|
|
62
62
|
```text
|
|
63
63
|
# Прямое серверное подключение
|
|
64
|
-
rag_session_autoconfigure(dump_if_missing=true, dump_connection_value="
|
|
64
|
+
rag_session_autoconfigure(dump_if_missing=true, dump_connection_value="<DIRECT_SERVER_INFOBASE>", dump_username="<DUMP_USERNAME>", dump_password="<DUMP_PASSWORD>")
|
|
65
65
|
|
|
66
66
|
# Из CF/CFE файлов
|
|
67
67
|
rag_session_autoconfigure(dump_if_missing=true, cf_files="config.cf", cfe_files="ext1.cfe,ext2.cfe")
|
|
@@ -8139,22 +8139,38 @@ async def _set_universal_report_quick_setting_by_titles(
|
|
|
8139
8139
|
warnings: list[str],
|
|
8140
8140
|
) -> bool:
|
|
8141
8141
|
local_warnings: list[str] = []
|
|
8142
|
+
value_norm = _normalize_match_text(value)
|
|
8142
8143
|
for title in titles:
|
|
8143
8144
|
try:
|
|
8144
8145
|
info = await _bridge_call_recorded(session_id, "field_info", {
|
|
8145
8146
|
"field_name": title,
|
|
8146
8147
|
"search_by_title": True,
|
|
8147
|
-
}, timeout=
|
|
8148
|
+
}, timeout=30)
|
|
8148
8149
|
if not isinstance(info, dict) or not info.get("found"):
|
|
8149
8150
|
raise RuntimeError(f"Поле не найдено по заголовку: {title}")
|
|
8150
8151
|
current = str(info.get("data_text") or "").strip()
|
|
8151
|
-
|
|
8152
|
+
current_norm = _normalize_match_text(current)
|
|
8153
|
+
if current == value or (value_norm and value_norm in current_norm):
|
|
8152
8154
|
return True
|
|
8155
|
+
# On some BSP report forms title lookup for "Объект" can match the
|
|
8156
|
+
# previous quick-setting row (for example the object-family field
|
|
8157
|
+
# currently containing "Справочники"). Do not overwrite such a row
|
|
8158
|
+
# with a catalog object name; try the next candidate title instead.
|
|
8159
|
+
if value_norm and "идентификаторыобъектовметаданных" in value_norm and current_norm in {
|
|
8160
|
+
"справочники",
|
|
8161
|
+
"справочник",
|
|
8162
|
+
"каталоги",
|
|
8163
|
+
}:
|
|
8164
|
+
local_warnings.append(
|
|
8165
|
+
f"Universal report quick setting {title!r} looked like object-family field"
|
|
8166
|
+
f" (current={current!r}); trying next title"
|
|
8167
|
+
)
|
|
8168
|
+
continue
|
|
8153
8169
|
field_name = str(info.get("name") or title)
|
|
8154
8170
|
await _bridge_call_recorded(session_id, "set_field_value", {
|
|
8155
8171
|
"field_name": field_name,
|
|
8156
8172
|
"value": value,
|
|
8157
|
-
}, timeout=
|
|
8173
|
+
}, timeout=75)
|
|
8158
8174
|
return True
|
|
8159
8175
|
except Exception as exc:
|
|
8160
8176
|
local_warnings.append(f"Universal report quick setting {title!r} was not set by title: {exc}")
|
|
@@ -8201,15 +8217,153 @@ async def _configure_universal_report_metadata_settings(session_id: str, query:
|
|
|
8201
8217
|
"Universal report selected fields are not enabled in UI settings;"
|
|
8202
8218
|
f" leaving report settings unchanged and relying on parse/post-filtering: {', '.join(disabled)}"
|
|
8203
8219
|
)
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
|
|
8220
|
+
# Do not add report-level filters here. On live BSP Universal Report forms
|
|
8221
|
+
# the filter-add button can open the formula editor instead of the field
|
|
8222
|
+
# chooser, leaving the tool in an unrelated modal form. Correctness is
|
|
8223
|
+
# enforced by the confirmed report source plus parser-side validation and
|
|
8224
|
+
# metadata-row filtering; this keeps the user-visible report on the right
|
|
8225
|
+
# catalog without risking another noisy/stuck UI mutation.
|
|
8226
|
+
warnings.append("Universal report row filters were not mutated; using confirmed source and parser-side metadata filtering")
|
|
8209
8227
|
await _bridge_call_recorded(session_id, "click_button", {"name": "ЗакрытьИСформировать"}, timeout=35)
|
|
8210
8228
|
return warnings
|
|
8211
8229
|
|
|
8212
8230
|
|
|
8231
|
+
def _universal_report_metadata_source_title_found(value: Any) -> bool:
|
|
8232
|
+
if not isinstance(value, dict):
|
|
8233
|
+
return False
|
|
8234
|
+
diagnostics = value.get("client_diagnostics") if isinstance(value.get("client_diagnostics"), dict) else {}
|
|
8235
|
+
candidates = [
|
|
8236
|
+
value.get("title"),
|
|
8237
|
+
value.get("window_title_after"),
|
|
8238
|
+
value.get("window_title_before"),
|
|
8239
|
+
diagnostics.get("active_window_title"),
|
|
8240
|
+
diagnostics.get("modal_title"),
|
|
8241
|
+
]
|
|
8242
|
+
for item in candidates:
|
|
8243
|
+
normalized = _normalize_match_text(str(item or ""))
|
|
8244
|
+
if "идентификаторыобъектовметаданных" in normalized:
|
|
8245
|
+
return True
|
|
8246
|
+
return False
|
|
8247
|
+
|
|
8248
|
+
|
|
8249
|
+
def _active_window_looks_like_startup_noise(value: Any) -> bool:
|
|
8250
|
+
if not isinstance(value, dict):
|
|
8251
|
+
return False
|
|
8252
|
+
title = str(value.get("title") or "")
|
|
8253
|
+
form_name = str(value.get("form_name") or "")
|
|
8254
|
+
diagnostics = value.get("client_diagnostics") if isinstance(value.get("client_diagnostics"), dict) else {}
|
|
8255
|
+
diagnostic_title = str(diagnostics.get("active_window_title") or diagnostics.get("modal_title") or "")
|
|
8256
|
+
diagnostic_form = str(diagnostics.get("active_form_name") or diagnostics.get("modal_form_name") or "")
|
|
8257
|
+
return (
|
|
8258
|
+
title.startswith("Новое в версии")
|
|
8259
|
+
or diagnostic_title.startswith("Новое в версии")
|
|
8260
|
+
or "Справочник.Новости.Форма.ФормаНовости" in form_name
|
|
8261
|
+
or "Справочник.Новости.Форма.ФормаНовости" in diagnostic_form
|
|
8262
|
+
)
|
|
8263
|
+
|
|
8264
|
+
|
|
8265
|
+
async def _active_universal_report_window(session_id: str, warnings: list[str], *, timeout: int = 30) -> dict[str, Any]:
|
|
8266
|
+
navigation_link = "e1cib/app/Отчет.УниверсальныйОтчет"
|
|
8267
|
+
deadline = time.monotonic() + max(timeout, 1)
|
|
8268
|
+
last: dict[str, Any] = {}
|
|
8269
|
+
while time.monotonic() < deadline:
|
|
8270
|
+
try:
|
|
8271
|
+
active = await _bridge_call_recorded(session_id, "active_window", {}, timeout=8)
|
|
8272
|
+
if isinstance(active, dict):
|
|
8273
|
+
last = active
|
|
8274
|
+
title = str(active.get("title") or "")
|
|
8275
|
+
form_name = str(active.get("form_name") or "")
|
|
8276
|
+
if "Универсальный отчет" in title or form_name == "ОбщаяФорма.ФормаОтчета":
|
|
8277
|
+
return active
|
|
8278
|
+
if _active_window_looks_like_startup_noise(active):
|
|
8279
|
+
await _bridge_call_recorded(session_id, "close_form", {}, timeout=15)
|
|
8280
|
+
warnings.append("Startup/news form was closed before Universal report source selection")
|
|
8281
|
+
try:
|
|
8282
|
+
await _bridge_call_recorded(
|
|
8283
|
+
session_id,
|
|
8284
|
+
"open_navigation_link",
|
|
8285
|
+
{"navigation_link": navigation_link},
|
|
8286
|
+
timeout=20,
|
|
8287
|
+
)
|
|
8288
|
+
warnings.append("Universal report navigation was retried after closing startup/news form")
|
|
8289
|
+
except Exception as exc:
|
|
8290
|
+
warnings.append(f"Universal report navigation retry after startup/news form failed: {exc}")
|
|
8291
|
+
await asyncio.sleep(1)
|
|
8292
|
+
continue
|
|
8293
|
+
except Exception as exc:
|
|
8294
|
+
warnings.append(f"Universal report active-window wait probe failed: {exc}")
|
|
8295
|
+
await asyncio.sleep(1)
|
|
8296
|
+
return last
|
|
8297
|
+
|
|
8298
|
+
|
|
8299
|
+
async def _ensure_universal_report_metadata_source(session_id: str, warnings: list[str], open_result: Any) -> bool:
|
|
8300
|
+
if _universal_report_metadata_source_title_found(open_result):
|
|
8301
|
+
warnings.append("Universal report metadata-identifiers source confirmed by opened form title")
|
|
8302
|
+
return True
|
|
8303
|
+
try:
|
|
8304
|
+
active = await _active_universal_report_window(session_id, warnings)
|
|
8305
|
+
if _universal_report_metadata_source_title_found(active):
|
|
8306
|
+
warnings.append("Universal report metadata-identifiers source confirmed by active window title")
|
|
8307
|
+
return True
|
|
8308
|
+
except Exception as exc:
|
|
8309
|
+
warnings.append(f"Universal report active-window source validation failed: {exc}")
|
|
8310
|
+
warnings.append(
|
|
8311
|
+
"Universal report did not open on metadata-identifiers source; trying quick settings"
|
|
8312
|
+
)
|
|
8313
|
+
type_ok = await _set_universal_report_quick_setting_by_titles(
|
|
8314
|
+
session_id,
|
|
8315
|
+
["Тип объекта", "Тип данных", "Раздел"],
|
|
8316
|
+
"Справочники",
|
|
8317
|
+
warnings,
|
|
8318
|
+
)
|
|
8319
|
+
source_ok = await _set_universal_report_quick_setting_by_titles(
|
|
8320
|
+
session_id,
|
|
8321
|
+
["Объект", "Справочник", "Имя объекта"],
|
|
8322
|
+
"Идентификаторы объектов метаданных",
|
|
8323
|
+
warnings,
|
|
8324
|
+
)
|
|
8325
|
+
if not source_ok:
|
|
8326
|
+
source_ok = await _set_universal_report_quick_setting_by_titles(
|
|
8327
|
+
session_id,
|
|
8328
|
+
["Объект", "Справочник", "Имя объекта"],
|
|
8329
|
+
"ИдентификаторыОбъектовМетаданных",
|
|
8330
|
+
warnings,
|
|
8331
|
+
)
|
|
8332
|
+
if type_ok and not source_ok:
|
|
8333
|
+
warnings.append(
|
|
8334
|
+
"Universal report object-family quick setting was set, but metadata-identifiers object was not confirmed"
|
|
8335
|
+
)
|
|
8336
|
+
if source_ok:
|
|
8337
|
+
warnings.append("Universal report quick settings were used to select metadata-identifiers source")
|
|
8338
|
+
try:
|
|
8339
|
+
active = await _active_universal_report_window(session_id, warnings, timeout=20)
|
|
8340
|
+
if _universal_report_metadata_source_title_found(active):
|
|
8341
|
+
warnings.append("Universal report metadata-identifiers source confirmed after quick settings")
|
|
8342
|
+
return True
|
|
8343
|
+
warnings.append(
|
|
8344
|
+
"Universal report quick settings completed but metadata-identifiers source was not confirmed"
|
|
8345
|
+
)
|
|
8346
|
+
except Exception as exc:
|
|
8347
|
+
warnings.append(f"Universal report source confirmation after quick settings failed: {exc}")
|
|
8348
|
+
return False
|
|
8349
|
+
|
|
8350
|
+
|
|
8351
|
+
def _metadata_report_rows_look_like_identifiers(rows: list[dict[str, str]]) -> bool:
|
|
8352
|
+
if not rows:
|
|
8353
|
+
return False
|
|
8354
|
+
useful_full_names = 0
|
|
8355
|
+
technical_columns = 0
|
|
8356
|
+
for row in rows[:200]:
|
|
8357
|
+
if _row_value(row, "Полное имя", "ПолноеИмя", "СписокПолноеИмя"):
|
|
8358
|
+
technical_columns += 1
|
|
8359
|
+
item = _metadata_object_from_row(row)
|
|
8360
|
+
if _is_metadata_full_name_included(item.get("full_name", "")):
|
|
8361
|
+
useful_full_names += 1
|
|
8362
|
+
if useful_full_names >= 3:
|
|
8363
|
+
return True
|
|
8364
|
+
return technical_columns > 0 and useful_full_names > 0
|
|
8365
|
+
|
|
8366
|
+
|
|
8213
8367
|
async def _metadata_rows_from_universal_report(
|
|
8214
8368
|
session_id: str,
|
|
8215
8369
|
max_rows: int,
|
|
@@ -8229,42 +8383,43 @@ async def _metadata_rows_from_universal_report(
|
|
|
8229
8383
|
try:
|
|
8230
8384
|
open_result = await _bridge_call_recorded(session_id, "open_navigation_link", {"navigation_link": navigation_link})
|
|
8231
8385
|
await _close_message_box_from_command_diagnostics(session_id, open_result, warnings)
|
|
8232
|
-
|
|
8233
|
-
# On some live web/thin-client sessions the report opens already on the
|
|
8234
|
-
# required metadata-identifiers source, but title-based `field_info`
|
|
8235
|
-
# probing of quick settings makes the bridge unresponsive before the
|
|
8236
|
-
# report can be formed. Prefer the stable navigation-link source and
|
|
8237
|
-
# validate the produced XLSX contents after save.
|
|
8238
|
-
warnings.append(
|
|
8239
|
-
"Universal report quick settings probing skipped;"
|
|
8240
|
-
" using the source opened by the navigation link and validating XLSX rows"
|
|
8241
|
-
)
|
|
8242
|
-
# Do not open the Universal report settings form in the primary path.
|
|
8243
|
-
# Live thin-client/web sessions can visually open `ВсеНастройки` but
|
|
8244
|
-
# leave the test bridge unresponsive for minutes; adding the first
|
|
8245
|
-
# filter field can also end in `Потеряно соединение`. The primary path
|
|
8246
|
-
# must therefore form the report with the selected source and apply the
|
|
8247
|
-
# mandatory filtering/normalization on the Python side. Settings remain
|
|
8248
|
-
# available as a separate best-effort diagnostic helper, not as a
|
|
8249
|
-
# correctness-critical step of metadata cache building.
|
|
8250
|
-
warnings.append("Universal report settings UI skipped; filtering is applied after reading rows")
|
|
8251
|
-
# Avoid active_window probes before forming the report: on live web/thin
|
|
8252
|
-
# sessions they can make the bridge unresponsive even when the report
|
|
8253
|
-
# form is visually ready. If navigation returned no safe MessageBox
|
|
8254
|
-
# diagnostics, go straight to the form command.
|
|
8255
|
-
form_result = await _dangerous_bridge_call_recorded(
|
|
8386
|
+
source_configured = await _ensure_universal_report_metadata_source(
|
|
8256
8387
|
session_id,
|
|
8257
|
-
|
|
8258
|
-
|
|
8259
|
-
timeout=180,
|
|
8260
|
-
danger="metadata_objects_universal_report_form_may_block_thin_client",
|
|
8388
|
+
warnings,
|
|
8389
|
+
open_result,
|
|
8261
8390
|
)
|
|
8262
|
-
if
|
|
8391
|
+
if not source_configured:
|
|
8392
|
+
return [], [
|
|
8393
|
+
*warnings,
|
|
8394
|
+
(
|
|
8395
|
+
"Universal report metadata source was not confirmed or configured;"
|
|
8396
|
+
" refusing to read arbitrary current Universal report result"
|
|
8397
|
+
),
|
|
8398
|
+
]
|
|
8399
|
+
try:
|
|
8400
|
+
settings_warnings = await _configure_universal_report_metadata_settings(session_id, query)
|
|
8401
|
+
warnings.extend(settings_warnings)
|
|
8402
|
+
settings_applied = True
|
|
8403
|
+
except Exception as exc:
|
|
8404
|
+
settings_applied = False
|
|
8263
8405
|
warnings.append(
|
|
8264
|
-
"Universal report
|
|
8265
|
-
f"
|
|
8406
|
+
"Universal report settings UI failed; falling back to report formation only"
|
|
8407
|
+
f"; error={exc}"
|
|
8266
8408
|
)
|
|
8267
|
-
|
|
8409
|
+
if not settings_applied:
|
|
8410
|
+
form_result = await _dangerous_bridge_call_recorded(
|
|
8411
|
+
session_id,
|
|
8412
|
+
"click_button",
|
|
8413
|
+
{"name": "СформироватьОтчет"},
|
|
8414
|
+
timeout=180,
|
|
8415
|
+
danger="metadata_objects_universal_report_form_may_block_thin_client",
|
|
8416
|
+
)
|
|
8417
|
+
if isinstance(form_result, dict) and form_result.get("started_long_action"):
|
|
8418
|
+
warnings.append(
|
|
8419
|
+
"Universal report form action is still running or blocked the interface;"
|
|
8420
|
+
f" form_result={_truncate_value(form_result)}"
|
|
8421
|
+
)
|
|
8422
|
+
return [], warnings
|
|
8268
8423
|
ready, readiness_warnings, readiness = await _wait_tabular_document_ready(
|
|
8269
8424
|
session_id,
|
|
8270
8425
|
"ОтчетТабличныйДокумент",
|
|
@@ -8313,12 +8468,19 @@ async def _metadata_rows_from_universal_report(
|
|
|
8313
8468
|
except Exception as exc:
|
|
8314
8469
|
read_warnings.append(f"Universal report MXL save/read failed: {exc}")
|
|
8315
8470
|
if rows:
|
|
8316
|
-
|
|
8317
|
-
|
|
8318
|
-
|
|
8319
|
-
|
|
8320
|
-
|
|
8321
|
-
|
|
8471
|
+
if not _metadata_report_rows_look_like_identifiers(rows):
|
|
8472
|
+
read_warnings.append(
|
|
8473
|
+
"Universal report MXL parsed rows do not look like metadata identifiers;"
|
|
8474
|
+
" ignoring this report output"
|
|
8475
|
+
)
|
|
8476
|
+
rows = []
|
|
8477
|
+
else:
|
|
8478
|
+
warnings.extend(read_warnings)
|
|
8479
|
+
warnings.append(
|
|
8480
|
+
"Universal report MXL became parseable"
|
|
8481
|
+
f"; rows={readiness.get('rows')}; columns={readiness.get('columns')}; path={last_saved_path}"
|
|
8482
|
+
)
|
|
8483
|
+
return rows[:max_rows], warnings
|
|
8322
8484
|
|
|
8323
8485
|
report_path = Path("/tmp/answer42") / f"metadata_objects_{session_id}_{uuid.uuid4().hex}.xlsx"
|
|
8324
8486
|
try:
|
|
@@ -8348,9 +8510,15 @@ async def _metadata_rows_from_universal_report(
|
|
|
8348
8510
|
rows = _metadata_catalog_rows_from_xlsx(Path(selected_path))
|
|
8349
8511
|
except Exception as exc:
|
|
8350
8512
|
read_warnings.append(f"Universal report XLSX save/read failed: {exc}")
|
|
8513
|
+
if rows and not _metadata_report_rows_look_like_identifiers(rows):
|
|
8514
|
+
read_warnings.append(
|
|
8515
|
+
"Universal report XLSX parsed rows do not look like metadata identifiers;"
|
|
8516
|
+
" ignoring this report output"
|
|
8517
|
+
)
|
|
8518
|
+
rows = []
|
|
8351
8519
|
if not rows:
|
|
8352
8520
|
warning = (
|
|
8353
|
-
"Universal report returned no parseable metadata rows"
|
|
8521
|
+
"Universal report returned no parseable metadata identifier rows"
|
|
8354
8522
|
f" after ready state; last_saved_path={last_saved_path};"
|
|
8355
8523
|
f" readiness={_truncate_value(readiness)};"
|
|
8356
8524
|
f" save_result={_truncate_value(save_diagnostics)}"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{answer42-0.4.76 → answer42-0.4.78}/src/cf/DataProcessors/MCPTestManager/Ext/ObjectModule.bsl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{answer42-0.4.76 → answer42-0.4.78}/src/mcp_1c/assets/skills/answer42-universal-report/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|