@josephyan/qingflow-cli 0.2.0-beta.985 → 0.2.0-beta.987
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/README.md +2 -2
- package/docs/local-agent-install.md +70 -11
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/builder_facade/service.py +376 -19
- package/src/qingflow_mcp/cli/commands/auth.py +14 -43
- package/src/qingflow_mcp/cli/commands/workspace.py +8 -5
- package/src/qingflow_mcp/cli/formatters.py +19 -22
- package/src/qingflow_mcp/config.py +39 -0
- package/src/qingflow_mcp/errors.py +2 -2
- package/src/qingflow_mcp/public_surface.py +4 -6
- package/src/qingflow_mcp/response_trim.py +1 -8
- package/src/qingflow_mcp/server.py +1 -1
- package/src/qingflow_mcp/server_app_builder.py +4 -28
- package/src/qingflow_mcp/server_app_user.py +4 -28
- package/src/qingflow_mcp/session_store.py +31 -5
- package/src/qingflow_mcp/solution/compiler/form_compiler.py +2 -2
- package/src/qingflow_mcp/solution/executor.py +2 -2
- package/src/qingflow_mcp/tools/ai_builder_tools.py +117 -1
- package/src/qingflow_mcp/tools/app_tools.py +51 -1
- package/src/qingflow_mcp/tools/approval_tools.py +82 -1
- package/src/qingflow_mcp/tools/auth_tools.py +306 -288
- package/src/qingflow_mcp/tools/base.py +204 -4
- package/src/qingflow_mcp/tools/code_block_tools.py +21 -0
- package/src/qingflow_mcp/tools/custom_button_tools.py +24 -1
- package/src/qingflow_mcp/tools/directory_tools.py +28 -1
- package/src/qingflow_mcp/tools/feedback_tools.py +8 -0
- package/src/qingflow_mcp/tools/file_tools.py +25 -1
- package/src/qingflow_mcp/tools/import_tools.py +40 -1
- package/src/qingflow_mcp/tools/navigation_tools.py +34 -1
- package/src/qingflow_mcp/tools/package_tools.py +37 -1
- package/src/qingflow_mcp/tools/portal_tools.py +28 -1
- package/src/qingflow_mcp/tools/qingbi_report_tools.py +38 -1
- package/src/qingflow_mcp/tools/record_tools.py +255 -2
- package/src/qingflow_mcp/tools/repository_dev_tools.py +21 -2
- package/src/qingflow_mcp/tools/resource_read_tools.py +23 -1
- package/src/qingflow_mcp/tools/role_tools.py +19 -1
- package/src/qingflow_mcp/tools/solution_tools.py +56 -1
- package/src/qingflow_mcp/tools/task_context_tools.py +72 -1
- package/src/qingflow_mcp/tools/task_tools.py +49 -3
- package/src/qingflow_mcp/tools/view_tools.py +56 -1
- package/src/qingflow_mcp/tools/workflow_tools.py +65 -1
- package/src/qingflow_mcp/tools/workspace_tools.py +100 -217
|
@@ -21,7 +21,7 @@ from ..list_type_labels import (
|
|
|
21
21
|
get_system_view_id,
|
|
22
22
|
get_system_view_name,
|
|
23
23
|
)
|
|
24
|
-
from .base import ToolBase
|
|
24
|
+
from .base import ToolBase, tool_cn_name
|
|
25
25
|
from .directory_tools import _directory_has_more, _directory_items
|
|
26
26
|
|
|
27
27
|
|
|
@@ -240,7 +240,17 @@ FIELD_LOOKUP_STRIP_RE = re.compile(r"[\s_()()\[\]【】{}<>·/\\::-]+")
|
|
|
240
240
|
|
|
241
241
|
|
|
242
242
|
class RecordTools(ToolBase):
|
|
243
|
+
"""记录工具(中文名:记录读写与分析)。
|
|
244
|
+
|
|
245
|
+
类型:业务数据操作工具。
|
|
246
|
+
主要职责:
|
|
247
|
+
1. 提供记录 Schema、记录查询、记录 CRUD;
|
|
248
|
+
2. 提供成员/部门候选与代码块相关能力;
|
|
249
|
+
3. 提供面向分析场景的数据读取与字段归一化能力。
|
|
250
|
+
"""
|
|
251
|
+
|
|
243
252
|
def __init__(self, sessions, backend) -> None: # type: ignore[no-untyped-def]
|
|
253
|
+
"""执行内部辅助逻辑。"""
|
|
244
254
|
super().__init__(sessions, backend)
|
|
245
255
|
self._form_cache: dict[tuple[str, str, str, int | None], JSONObject] = {}
|
|
246
256
|
self._applicant_node_cache: dict[tuple[str, str], WorkflowNodeRef] = {}
|
|
@@ -250,6 +260,7 @@ class RecordTools(ToolBase):
|
|
|
250
260
|
self._relation_base_info_cache: dict[tuple[str, int], JSONObject] = {}
|
|
251
261
|
|
|
252
262
|
def register(self, mcp: FastMCP) -> None:
|
|
263
|
+
"""注册当前工具到 MCP 服务。"""
|
|
253
264
|
@mcp.tool()
|
|
254
265
|
def record_insert_schema_get(
|
|
255
266
|
app_key: str = "",
|
|
@@ -506,6 +517,7 @@ class RecordTools(ToolBase):
|
|
|
506
517
|
output_profile=output_profile,
|
|
507
518
|
)
|
|
508
519
|
|
|
520
|
+
@tool_cn_name("记录 Schema")
|
|
509
521
|
def record_schema_get(
|
|
510
522
|
self,
|
|
511
523
|
*,
|
|
@@ -518,6 +530,7 @@ class RecordTools(ToolBase):
|
|
|
518
530
|
view_name: str | None = None,
|
|
519
531
|
output_profile: str = "normal",
|
|
520
532
|
) -> JSONObject:
|
|
533
|
+
"""执行记录相关逻辑。"""
|
|
521
534
|
if not app_key:
|
|
522
535
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
523
536
|
normalized_schema_mode = schema_mode.strip().lower()
|
|
@@ -630,6 +643,7 @@ class RecordTools(ToolBase):
|
|
|
630
643
|
|
|
631
644
|
return self._run_record_tool(profile, runner)
|
|
632
645
|
|
|
646
|
+
@tool_cn_name("新增记录 Schema")
|
|
633
647
|
def record_insert_schema_get_public(
|
|
634
648
|
self,
|
|
635
649
|
*,
|
|
@@ -637,6 +651,7 @@ class RecordTools(ToolBase):
|
|
|
637
651
|
app_key: str,
|
|
638
652
|
output_profile: str = "normal",
|
|
639
653
|
) -> JSONObject:
|
|
654
|
+
"""执行记录相关逻辑。"""
|
|
640
655
|
if not app_key:
|
|
641
656
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
642
657
|
normalized_output_profile = self._normalize_public_output_profile(output_profile)
|
|
@@ -745,6 +760,7 @@ class RecordTools(ToolBase):
|
|
|
745
760
|
|
|
746
761
|
return self._run_record_tool(profile, runner)
|
|
747
762
|
|
|
763
|
+
@tool_cn_name("浏览记录 Schema")
|
|
748
764
|
def record_browse_schema_get_public(
|
|
749
765
|
self,
|
|
750
766
|
*,
|
|
@@ -753,6 +769,7 @@ class RecordTools(ToolBase):
|
|
|
753
769
|
view_id: str,
|
|
754
770
|
output_profile: str = "normal",
|
|
755
771
|
) -> JSONObject:
|
|
772
|
+
"""执行记录相关逻辑。"""
|
|
756
773
|
return self.record_schema_get(
|
|
757
774
|
profile=profile,
|
|
758
775
|
app_key=app_key,
|
|
@@ -761,6 +778,7 @@ class RecordTools(ToolBase):
|
|
|
761
778
|
output_profile=output_profile,
|
|
762
779
|
)
|
|
763
780
|
|
|
781
|
+
@tool_cn_name("更新记录 Schema")
|
|
764
782
|
def record_update_schema_get_public(
|
|
765
783
|
self,
|
|
766
784
|
*,
|
|
@@ -769,6 +787,7 @@ class RecordTools(ToolBase):
|
|
|
769
787
|
record_id: int,
|
|
770
788
|
output_profile: str = "normal",
|
|
771
789
|
) -> JSONObject:
|
|
790
|
+
"""执行记录相关逻辑。"""
|
|
772
791
|
if not app_key:
|
|
773
792
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
774
793
|
if record_id <= 0:
|
|
@@ -981,6 +1000,7 @@ class RecordTools(ToolBase):
|
|
|
981
1000
|
view_probe_summary: list[JSONObject],
|
|
982
1001
|
ambiguous_fields: list[JSONObject],
|
|
983
1002
|
) -> JSONObject:
|
|
1003
|
+
"""执行内部辅助逻辑。"""
|
|
984
1004
|
response: JSONObject = {
|
|
985
1005
|
"profile": profile,
|
|
986
1006
|
"ws_id": ws_id,
|
|
@@ -1010,7 +1030,9 @@ class RecordTools(ToolBase):
|
|
|
1010
1030
|
ws_id: int | None,
|
|
1011
1031
|
required_override: bool | None,
|
|
1012
1032
|
linkage_payloads_by_field_id: dict[str, JSONObject] | None = None,
|
|
1033
|
+
include_field_id: bool = True,
|
|
1013
1034
|
) -> JSONObject:
|
|
1035
|
+
"""执行内部辅助逻辑。"""
|
|
1014
1036
|
kind = self._ready_schema_kind(field)
|
|
1015
1037
|
row_fields: list[JSONObject] = []
|
|
1016
1038
|
if kind == "subtable":
|
|
@@ -1025,11 +1047,12 @@ class RecordTools(ToolBase):
|
|
|
1025
1047
|
else:
|
|
1026
1048
|
required = bool(required_override) if required_override is not None else bool(field.required)
|
|
1027
1049
|
payload: JSONObject = {
|
|
1028
|
-
"field_id": field.que_id,
|
|
1029
1050
|
"title": field.que_title,
|
|
1030
1051
|
"kind": kind,
|
|
1031
1052
|
"required": required,
|
|
1032
1053
|
}
|
|
1054
|
+
if include_field_id:
|
|
1055
|
+
payload["field_id"] = field.que_id
|
|
1033
1056
|
if kind in {"single_select", "multi_select"} and field.options:
|
|
1034
1057
|
payload["options"] = list(field.options)
|
|
1035
1058
|
if kind in {"member", "department", "relation"}:
|
|
@@ -1077,6 +1100,7 @@ class RecordTools(ToolBase):
|
|
|
1077
1100
|
reason: str,
|
|
1078
1101
|
linkage_payloads_by_field_id: dict[str, JSONObject] | None = None,
|
|
1079
1102
|
) -> JSONObject:
|
|
1103
|
+
"""执行内部辅助逻辑。"""
|
|
1080
1104
|
payload = self._ready_schema_field_payload(
|
|
1081
1105
|
profile,
|
|
1082
1106
|
context,
|
|
@@ -1084,6 +1108,7 @@ class RecordTools(ToolBase):
|
|
|
1084
1108
|
ws_id=ws_id,
|
|
1085
1109
|
required_override=True,
|
|
1086
1110
|
linkage_payloads_by_field_id=linkage_payloads_by_field_id,
|
|
1111
|
+
include_field_id=False,
|
|
1087
1112
|
)
|
|
1088
1113
|
payload["reason"] = reason
|
|
1089
1114
|
self._attach_ready_schema_linkage(
|
|
@@ -1102,6 +1127,7 @@ class RecordTools(ToolBase):
|
|
|
1102
1127
|
linkage_payloads_by_field_id: dict[str, JSONObject] | None,
|
|
1103
1128
|
role_override: str | None = None,
|
|
1104
1129
|
) -> None:
|
|
1130
|
+
"""执行内部辅助逻辑。"""
|
|
1105
1131
|
if not linkage_payloads_by_field_id:
|
|
1106
1132
|
return
|
|
1107
1133
|
linkage_payload = linkage_payloads_by_field_id.get(field_id)
|
|
@@ -1118,6 +1144,7 @@ class RecordTools(ToolBase):
|
|
|
1118
1144
|
*,
|
|
1119
1145
|
runtime_linked_field_ids: set[str],
|
|
1120
1146
|
) -> bool:
|
|
1147
|
+
"""执行内部辅助逻辑。"""
|
|
1121
1148
|
if not bool(field.required) or bool(field.system) or not bool(field.readonly):
|
|
1122
1149
|
return False
|
|
1123
1150
|
if str(field.que_id) not in runtime_linked_field_ids:
|
|
@@ -1139,6 +1166,7 @@ class RecordTools(ToolBase):
|
|
|
1139
1166
|
ws_id: int | None,
|
|
1140
1167
|
linkage_payloads_by_field_id: dict[str, JSONObject] | None = None,
|
|
1141
1168
|
) -> list[JSONObject]:
|
|
1169
|
+
"""执行内部辅助逻辑。"""
|
|
1142
1170
|
raw = field.raw if isinstance(field.raw, dict) else {}
|
|
1143
1171
|
columns_source = raw.get("subQuestions")
|
|
1144
1172
|
if isinstance(columns_source, list):
|
|
@@ -1161,11 +1189,13 @@ class RecordTools(ToolBase):
|
|
|
1161
1189
|
ws_id=ws_id,
|
|
1162
1190
|
required_override=bool(subfield.required),
|
|
1163
1191
|
linkage_payloads_by_field_id=linkage_payloads_by_field_id,
|
|
1192
|
+
include_field_id=False,
|
|
1164
1193
|
)
|
|
1165
1194
|
)
|
|
1166
1195
|
return payloads
|
|
1167
1196
|
|
|
1168
1197
|
def _ready_schema_kind(self, field: FormField) -> str:
|
|
1198
|
+
"""执行内部辅助逻辑。"""
|
|
1169
1199
|
write_format = _write_format_for_field(field)
|
|
1170
1200
|
write_kind = _normalize_optional_text(write_format.get("kind")) or "scalar_text"
|
|
1171
1201
|
if write_kind == "subtable_rows":
|
|
@@ -1198,6 +1228,7 @@ class RecordTools(ToolBase):
|
|
|
1198
1228
|
return "text"
|
|
1199
1229
|
|
|
1200
1230
|
def _ready_schema_template_value(self, field_payload: JSONObject) -> JSONValue:
|
|
1231
|
+
"""执行内部辅助逻辑。"""
|
|
1201
1232
|
kind = _normalize_optional_text(field_payload.get("kind")) or "text"
|
|
1202
1233
|
if kind == "number":
|
|
1203
1234
|
return "<number>"
|
|
@@ -1243,6 +1274,7 @@ class RecordTools(ToolBase):
|
|
|
1243
1274
|
]
|
|
1244
1275
|
return "<text>"
|
|
1245
1276
|
|
|
1277
|
+
@tool_cn_name("成员候选项")
|
|
1246
1278
|
def record_member_candidates(
|
|
1247
1279
|
self,
|
|
1248
1280
|
*,
|
|
@@ -1256,6 +1288,7 @@ class RecordTools(ToolBase):
|
|
|
1256
1288
|
page_num: int,
|
|
1257
1289
|
page_size: int,
|
|
1258
1290
|
) -> JSONObject:
|
|
1291
|
+
"""执行记录相关逻辑。"""
|
|
1259
1292
|
if not app_key:
|
|
1260
1293
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
1261
1294
|
if field_id <= 0:
|
|
@@ -1345,6 +1378,7 @@ class RecordTools(ToolBase):
|
|
|
1345
1378
|
|
|
1346
1379
|
return self._run_record_tool(profile, runner)
|
|
1347
1380
|
|
|
1381
|
+
@tool_cn_name("部门候选项")
|
|
1348
1382
|
def record_department_candidates(
|
|
1349
1383
|
self,
|
|
1350
1384
|
*,
|
|
@@ -1358,6 +1392,7 @@ class RecordTools(ToolBase):
|
|
|
1358
1392
|
page_num: int,
|
|
1359
1393
|
page_size: int,
|
|
1360
1394
|
) -> JSONObject:
|
|
1395
|
+
"""执行记录相关逻辑。"""
|
|
1361
1396
|
if not app_key:
|
|
1362
1397
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
1363
1398
|
if field_id <= 0:
|
|
@@ -1464,6 +1499,7 @@ class RecordTools(ToolBase):
|
|
|
1464
1499
|
|
|
1465
1500
|
return self._run_record_tool(profile, runner)
|
|
1466
1501
|
|
|
1502
|
+
@tool_cn_name("记录分析")
|
|
1467
1503
|
def record_analyze(
|
|
1468
1504
|
self,
|
|
1469
1505
|
*,
|
|
@@ -1481,6 +1517,7 @@ class RecordTools(ToolBase):
|
|
|
1481
1517
|
view_name: str | None = None,
|
|
1482
1518
|
output_profile: str = "normal",
|
|
1483
1519
|
) -> JSONObject:
|
|
1520
|
+
"""执行记录相关逻辑。"""
|
|
1484
1521
|
if not app_key:
|
|
1485
1522
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
1486
1523
|
if limit <= 0:
|
|
@@ -1551,6 +1588,7 @@ class RecordTools(ToolBase):
|
|
|
1551
1588
|
|
|
1552
1589
|
return self._run_record_tool(profile, runner)
|
|
1553
1590
|
|
|
1591
|
+
@tool_cn_name("记录列表")
|
|
1554
1592
|
def record_list(
|
|
1555
1593
|
self,
|
|
1556
1594
|
*,
|
|
@@ -1567,6 +1605,7 @@ class RecordTools(ToolBase):
|
|
|
1567
1605
|
view_name: str | None = None,
|
|
1568
1606
|
output_profile: str = "normal",
|
|
1569
1607
|
) -> JSONObject:
|
|
1608
|
+
"""执行记录相关逻辑。"""
|
|
1570
1609
|
normalized_output_profile = self._normalize_public_output_profile(output_profile, allow_normalized=True)
|
|
1571
1610
|
if not app_key:
|
|
1572
1611
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
@@ -1708,6 +1747,7 @@ class RecordTools(ToolBase):
|
|
|
1708
1747
|
}
|
|
1709
1748
|
return response
|
|
1710
1749
|
|
|
1750
|
+
@tool_cn_name("记录详情")
|
|
1711
1751
|
def record_get_public(
|
|
1712
1752
|
self,
|
|
1713
1753
|
*,
|
|
@@ -1719,6 +1759,7 @@ class RecordTools(ToolBase):
|
|
|
1719
1759
|
workflow_node_id: int | None = None,
|
|
1720
1760
|
output_profile: str = "normal",
|
|
1721
1761
|
) -> JSONObject:
|
|
1762
|
+
"""执行记录相关逻辑。"""
|
|
1722
1763
|
normalized_output_profile = self._normalize_public_output_profile(output_profile, allow_normalized=True)
|
|
1723
1764
|
if record_id <= 0:
|
|
1724
1765
|
raise_tool_error(QingflowApiError.config_error("record_id must be positive"))
|
|
@@ -1851,6 +1892,7 @@ class RecordTools(ToolBase):
|
|
|
1851
1892
|
|
|
1852
1893
|
return self._run_record_tool(profile, runner)
|
|
1853
1894
|
|
|
1895
|
+
@tool_cn_name("新增记录")
|
|
1854
1896
|
def record_insert_public(
|
|
1855
1897
|
self,
|
|
1856
1898
|
*,
|
|
@@ -1860,6 +1902,7 @@ class RecordTools(ToolBase):
|
|
|
1860
1902
|
verify_write: bool = True,
|
|
1861
1903
|
output_profile: str = "normal",
|
|
1862
1904
|
) -> JSONObject:
|
|
1905
|
+
"""执行记录相关逻辑。"""
|
|
1863
1906
|
normalized_output_profile = self._normalize_public_output_profile(output_profile)
|
|
1864
1907
|
if not app_key:
|
|
1865
1908
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
@@ -1926,6 +1969,7 @@ class RecordTools(ToolBase):
|
|
|
1926
1969
|
preflight=raw_preflight,
|
|
1927
1970
|
)
|
|
1928
1971
|
|
|
1972
|
+
@tool_cn_name("更新记录")
|
|
1929
1973
|
def record_update_public(
|
|
1930
1974
|
self,
|
|
1931
1975
|
*,
|
|
@@ -1938,6 +1982,7 @@ class RecordTools(ToolBase):
|
|
|
1938
1982
|
verify_write: bool = True,
|
|
1939
1983
|
output_profile: str = "normal",
|
|
1940
1984
|
) -> JSONObject:
|
|
1985
|
+
"""执行记录相关逻辑。"""
|
|
1941
1986
|
normalized_output_profile = self._normalize_public_output_profile(output_profile)
|
|
1942
1987
|
if not app_key:
|
|
1943
1988
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
@@ -1982,6 +2027,7 @@ class RecordTools(ToolBase):
|
|
|
1982
2027
|
verify_write: bool,
|
|
1983
2028
|
output_profile: str,
|
|
1984
2029
|
) -> JSONObject:
|
|
2030
|
+
"""执行内部辅助逻辑。"""
|
|
1985
2031
|
raw_preflight = self._preflight_record_update_with_auto_view(
|
|
1986
2032
|
profile=profile,
|
|
1987
2033
|
app_key=app_key,
|
|
@@ -2047,6 +2093,7 @@ class RecordTools(ToolBase):
|
|
|
2047
2093
|
verify_write: bool,
|
|
2048
2094
|
output_profile: str,
|
|
2049
2095
|
) -> JSONObject:
|
|
2096
|
+
"""执行内部辅助逻辑。"""
|
|
2050
2097
|
preflight_responses = [
|
|
2051
2098
|
self._record_update_public_preflight_response(
|
|
2052
2099
|
profile=profile,
|
|
@@ -2115,6 +2162,7 @@ class RecordTools(ToolBase):
|
|
|
2115
2162
|
fields: JSONObject,
|
|
2116
2163
|
output_profile: str,
|
|
2117
2164
|
) -> JSONObject:
|
|
2165
|
+
"""执行内部辅助逻辑。"""
|
|
2118
2166
|
raw_preflight = self._preflight_record_update_with_auto_view(
|
|
2119
2167
|
profile=profile,
|
|
2120
2168
|
app_key=app_key,
|
|
@@ -2157,6 +2205,7 @@ class RecordTools(ToolBase):
|
|
|
2157
2205
|
fields: JSONObject | None,
|
|
2158
2206
|
items: list[JSONObject] | None,
|
|
2159
2207
|
) -> list[JSONObject]:
|
|
2208
|
+
"""执行内部辅助逻辑。"""
|
|
2160
2209
|
if record_id is not None or fields is not None:
|
|
2161
2210
|
raise_tool_error(
|
|
2162
2211
|
QingflowApiError.config_error("record_update batch mode does not accept record_id or fields")
|
|
@@ -2191,6 +2240,7 @@ class RecordTools(ToolBase):
|
|
|
2191
2240
|
output_profile: str,
|
|
2192
2241
|
dry_run: bool,
|
|
2193
2242
|
) -> JSONObject:
|
|
2243
|
+
"""执行内部辅助逻辑。"""
|
|
2194
2244
|
summary = self._record_update_batch_summary(responses)
|
|
2195
2245
|
batch_items = [self._record_update_batch_item_from_response(response, output_profile=output_profile) for response in responses]
|
|
2196
2246
|
status, ok, message = self._record_update_batch_envelope_status(summary=summary, dry_run=dry_run)
|
|
@@ -2214,6 +2264,7 @@ class RecordTools(ToolBase):
|
|
|
2214
2264
|
}
|
|
2215
2265
|
|
|
2216
2266
|
def _record_update_batch_summary(self, responses: list[JSONObject]) -> JSONObject:
|
|
2267
|
+
"""执行内部辅助逻辑。"""
|
|
2217
2268
|
summary: JSONObject = {
|
|
2218
2269
|
"total": len(responses),
|
|
2219
2270
|
"ready_count": 0,
|
|
@@ -2250,6 +2301,7 @@ class RecordTools(ToolBase):
|
|
|
2250
2301
|
return summary
|
|
2251
2302
|
|
|
2252
2303
|
def _record_update_batch_envelope_status(self, *, summary: JSONObject, dry_run: bool) -> tuple[str, bool, str]:
|
|
2304
|
+
"""执行内部辅助逻辑。"""
|
|
2253
2305
|
if int(summary["blocked_count"]) > 0:
|
|
2254
2306
|
return "blocked", False, "batch update preflight blocked"
|
|
2255
2307
|
if int(summary["confirmation_count"]) > 0:
|
|
@@ -2261,6 +2313,7 @@ class RecordTools(ToolBase):
|
|
|
2261
2313
|
return "success", True, "batch update completed"
|
|
2262
2314
|
|
|
2263
2315
|
def _record_update_batch_item_from_response(self, response: JSONObject, *, output_profile: str) -> JSONObject:
|
|
2316
|
+
"""执行内部辅助逻辑。"""
|
|
2264
2317
|
data = cast(JSONObject, response.get("data", {}))
|
|
2265
2318
|
item: JSONObject = {
|
|
2266
2319
|
"resource": data.get("resource"),
|
|
@@ -2292,6 +2345,7 @@ class RecordTools(ToolBase):
|
|
|
2292
2345
|
fields: JSONObject,
|
|
2293
2346
|
force_refresh_form: bool,
|
|
2294
2347
|
) -> JSONObject:
|
|
2348
|
+
"""执行内部辅助逻辑。"""
|
|
2295
2349
|
def runner(session_profile, context):
|
|
2296
2350
|
request_route = self._request_route_payload(context)
|
|
2297
2351
|
def build_once(*, effective_force_refresh: bool) -> JSONObject:
|
|
@@ -2583,6 +2637,7 @@ class RecordTools(ToolBase):
|
|
|
2583
2637
|
matched_routes: list[AccessibleViewRoute],
|
|
2584
2638
|
force_refresh_form: bool,
|
|
2585
2639
|
) -> JSONObject | None:
|
|
2640
|
+
"""执行内部辅助逻辑。"""
|
|
2586
2641
|
if len(matched_routes) < 2:
|
|
2587
2642
|
return None
|
|
2588
2643
|
|
|
@@ -2745,6 +2800,7 @@ class RecordTools(ToolBase):
|
|
|
2745
2800
|
view_probe_summary: list[JSONObject],
|
|
2746
2801
|
template: JSONObject | None = None,
|
|
2747
2802
|
) -> JSONObject:
|
|
2803
|
+
"""执行内部辅助逻辑。"""
|
|
2748
2804
|
blocked_data: JSONObject = dict(template or {})
|
|
2749
2805
|
validation = blocked_data.get("validation")
|
|
2750
2806
|
if not isinstance(validation, dict):
|
|
@@ -2788,6 +2844,7 @@ class RecordTools(ToolBase):
|
|
|
2788
2844
|
context, # type: ignore[no-untyped-def]
|
|
2789
2845
|
app_key: str,
|
|
2790
2846
|
) -> list[AccessibleViewRoute]:
|
|
2847
|
+
"""执行内部辅助逻辑。"""
|
|
2791
2848
|
candidates: list[AccessibleViewRoute] = []
|
|
2792
2849
|
for view_id, list_type, name in SYSTEM_VIEW_DEFINITIONS:
|
|
2793
2850
|
candidates.append(
|
|
@@ -2996,6 +3053,7 @@ class RecordTools(ToolBase):
|
|
|
2996
3053
|
*,
|
|
2997
3054
|
resolved_view: AccessibleViewRoute,
|
|
2998
3055
|
) -> bool:
|
|
3056
|
+
"""执行内部辅助逻辑。"""
|
|
2999
3057
|
if resolved_view.kind == "system":
|
|
3000
3058
|
return True
|
|
3001
3059
|
return self._matches_view_selection(
|
|
@@ -3005,6 +3063,7 @@ class RecordTools(ToolBase):
|
|
|
3005
3063
|
dept_member_cache={},
|
|
3006
3064
|
)
|
|
3007
3065
|
|
|
3066
|
+
@tool_cn_name("删除记录")
|
|
3008
3067
|
def record_delete_public(
|
|
3009
3068
|
self,
|
|
3010
3069
|
*,
|
|
@@ -3014,6 +3073,7 @@ class RecordTools(ToolBase):
|
|
|
3014
3073
|
record_ids: list[int] | None = None,
|
|
3015
3074
|
output_profile: str = "normal",
|
|
3016
3075
|
) -> JSONObject:
|
|
3076
|
+
"""执行记录相关逻辑。"""
|
|
3017
3077
|
normalized_output_profile = self._normalize_public_output_profile(output_profile)
|
|
3018
3078
|
if not app_key:
|
|
3019
3079
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
@@ -3038,6 +3098,7 @@ class RecordTools(ToolBase):
|
|
|
3038
3098
|
preflight=None,
|
|
3039
3099
|
)
|
|
3040
3100
|
|
|
3101
|
+
@tool_cn_name("写入记录")
|
|
3041
3102
|
def record_write(
|
|
3042
3103
|
self,
|
|
3043
3104
|
*,
|
|
@@ -3057,6 +3118,7 @@ class RecordTools(ToolBase):
|
|
|
3057
3118
|
output_profile: str = "normal",
|
|
3058
3119
|
mode: str | None = None,
|
|
3059
3120
|
) -> JSONObject:
|
|
3121
|
+
"""执行记录相关逻辑。"""
|
|
3060
3122
|
normalized_output_profile = self._normalize_public_output_profile(output_profile)
|
|
3061
3123
|
normalized_operation = operation.strip().lower()
|
|
3062
3124
|
if normalized_operation not in {"insert", "update", "delete"}:
|
|
@@ -3261,6 +3323,7 @@ class RecordTools(ToolBase):
|
|
|
3261
3323
|
schema_mode: str = "applicant",
|
|
3262
3324
|
browse_writable: bool | None = None,
|
|
3263
3325
|
) -> JSONObject: # type: ignore[no-untyped-def]
|
|
3326
|
+
"""执行内部辅助逻辑。"""
|
|
3264
3327
|
write_hints = self._schema_write_hints(field)
|
|
3265
3328
|
if schema_mode == "applicant":
|
|
3266
3329
|
writable = write_hints["writable"]
|
|
@@ -3305,6 +3368,7 @@ class RecordTools(ToolBase):
|
|
|
3305
3368
|
return payload
|
|
3306
3369
|
|
|
3307
3370
|
def _schema_role_hints(self, field: FormField) -> JSONObject:
|
|
3371
|
+
"""执行内部辅助逻辑。"""
|
|
3308
3372
|
field_family = self._schema_field_family(field)
|
|
3309
3373
|
time_candidate = field.que_type in DATE_QUE_TYPES
|
|
3310
3374
|
identifier_like = self._schema_is_identifier_like(field, field_family=field_family)
|
|
@@ -3323,6 +3387,7 @@ class RecordTools(ToolBase):
|
|
|
3323
3387
|
}
|
|
3324
3388
|
|
|
3325
3389
|
def _schema_write_hints(self, field: FormField) -> JSONObject:
|
|
3390
|
+
"""执行内部辅助逻辑。"""
|
|
3326
3391
|
write_format = _write_format_for_field(field)
|
|
3327
3392
|
kind = _normalize_optional_text(write_format.get("kind")) or "scalar_text"
|
|
3328
3393
|
support_level = _normalize_optional_text(write_format.get("support_level")) or "full"
|
|
@@ -3350,6 +3415,7 @@ class RecordTools(ToolBase):
|
|
|
3350
3415
|
}
|
|
3351
3416
|
|
|
3352
3417
|
def _schema_write_kind(self, kind: str) -> str:
|
|
3418
|
+
"""执行内部辅助逻辑。"""
|
|
3353
3419
|
mapping = {
|
|
3354
3420
|
"single_select": "select",
|
|
3355
3421
|
"multi_select": "select",
|
|
@@ -3373,6 +3439,7 @@ class RecordTools(ToolBase):
|
|
|
3373
3439
|
target_app_key: str,
|
|
3374
3440
|
ws_id: int | None,
|
|
3375
3441
|
) -> str | None:
|
|
3442
|
+
"""执行内部辅助逻辑。"""
|
|
3376
3443
|
cache_key = (profile, ws_id, target_app_key)
|
|
3377
3444
|
if cache_key in self._app_name_cache:
|
|
3378
3445
|
return self._app_name_cache[cache_key]
|
|
@@ -3391,6 +3458,7 @@ class RecordTools(ToolBase):
|
|
|
3391
3458
|
return name
|
|
3392
3459
|
|
|
3393
3460
|
def _lookup_context_answers(self, state: LookupResolutionState) -> list[JSONObject]:
|
|
3461
|
+
"""执行内部辅助逻辑。"""
|
|
3394
3462
|
merged: dict[int, JSONObject] = {}
|
|
3395
3463
|
ordered_ids: list[int] = []
|
|
3396
3464
|
for answer in state.base_answers:
|
|
@@ -3414,6 +3482,7 @@ class RecordTools(ToolBase):
|
|
|
3414
3482
|
return [merged[que_id] for que_id in ordered_ids]
|
|
3415
3483
|
|
|
3416
3484
|
def _answers_to_lookup_key_values(self, answers: list[JSONObject], index: FieldIndex) -> list[JSONObject]:
|
|
3485
|
+
"""执行内部辅助逻辑。"""
|
|
3417
3486
|
values: list[JSONObject] = []
|
|
3418
3487
|
for answer in answers:
|
|
3419
3488
|
if not isinstance(answer, dict):
|
|
@@ -3425,6 +3494,7 @@ class RecordTools(ToolBase):
|
|
|
3425
3494
|
return values
|
|
3426
3495
|
|
|
3427
3496
|
def _answer_to_lookup_key_value(self, answer: JSONObject, index: FieldIndex) -> JSONObject | None:
|
|
3497
|
+
"""执行内部辅助逻辑。"""
|
|
3428
3498
|
que_id = _coerce_count(answer.get("queId", answer.get("que_id")))
|
|
3429
3499
|
if que_id is None or que_id <= 0:
|
|
3430
3500
|
return None
|
|
@@ -3456,6 +3526,7 @@ class RecordTools(ToolBase):
|
|
|
3456
3526
|
}
|
|
3457
3527
|
|
|
3458
3528
|
def _answer_values_to_lookup_values(self, answer: JSONObject, field: FormField) -> list[str]:
|
|
3529
|
+
"""执行内部辅助逻辑。"""
|
|
3459
3530
|
if field.que_type in RELATION_QUE_TYPES:
|
|
3460
3531
|
return _relation_ids_from_answer(answer)
|
|
3461
3532
|
raw_values = answer.get("values")
|
|
@@ -3492,6 +3563,7 @@ class RecordTools(ToolBase):
|
|
|
3492
3563
|
return normalized
|
|
3493
3564
|
|
|
3494
3565
|
def _lookup_key_que_values(self, state: LookupResolutionState) -> list[JSONObject]:
|
|
3566
|
+
"""执行内部辅助逻辑。"""
|
|
3495
3567
|
answers = self._lookup_context_answers(state)
|
|
3496
3568
|
if not answers:
|
|
3497
3569
|
return []
|
|
@@ -3506,6 +3578,7 @@ class RecordTools(ToolBase):
|
|
|
3506
3578
|
page_num: int = 1,
|
|
3507
3579
|
page_size: int = LOOKUP_RELATION_FILTER_PAGE_SIZE,
|
|
3508
3580
|
) -> JSONObject:
|
|
3581
|
+
"""执行内部辅助逻辑。"""
|
|
3509
3582
|
payload: JSONObject = {
|
|
3510
3583
|
"role": 1,
|
|
3511
3584
|
"pageNum": page_num,
|
|
@@ -3525,6 +3598,7 @@ class RecordTools(ToolBase):
|
|
|
3525
3598
|
return payload
|
|
3526
3599
|
|
|
3527
3600
|
def _relation_base_info(self, context, *, app_key: str, field: FormField) -> JSONObject | None: # type: ignore[no-untyped-def]
|
|
3601
|
+
"""执行内部辅助逻辑。"""
|
|
3528
3602
|
cache_key = (app_key, field.que_id)
|
|
3529
3603
|
if cache_key in self._relation_base_info_cache:
|
|
3530
3604
|
return self._relation_base_info_cache[cache_key]
|
|
@@ -3544,6 +3618,7 @@ class RecordTools(ToolBase):
|
|
|
3544
3618
|
app_key: str,
|
|
3545
3619
|
field: FormField,
|
|
3546
3620
|
) -> list[JSONObject]:
|
|
3621
|
+
"""执行内部辅助逻辑。"""
|
|
3547
3622
|
direct = _relation_searchable_fields_for_question(field.raw)
|
|
3548
3623
|
return direct
|
|
3549
3624
|
|
|
@@ -3554,6 +3629,7 @@ class RecordTools(ToolBase):
|
|
|
3554
3629
|
field: FormField,
|
|
3555
3630
|
app_key: str,
|
|
3556
3631
|
) -> list[tuple[JSONObject, FormField]]:
|
|
3632
|
+
"""执行内部辅助逻辑。"""
|
|
3557
3633
|
searchable_fields = self._relation_searchable_fields_for_field(context, app_key=app_key, field=field)
|
|
3558
3634
|
if not searchable_fields:
|
|
3559
3635
|
return []
|
|
@@ -3607,6 +3683,7 @@ class RecordTools(ToolBase):
|
|
|
3607
3683
|
page_num: int = 1,
|
|
3608
3684
|
page_size: int = LOOKUP_RELATION_FILTER_PAGE_SIZE,
|
|
3609
3685
|
) -> JSONObject:
|
|
3686
|
+
"""执行内部辅助逻辑。"""
|
|
3610
3687
|
payload: JSONObject = {
|
|
3611
3688
|
"appKey": state.app_key,
|
|
3612
3689
|
"queId": field.que_id,
|
|
@@ -3628,6 +3705,7 @@ class RecordTools(ToolBase):
|
|
|
3628
3705
|
return payload
|
|
3629
3706
|
|
|
3630
3707
|
def _normalize_relation_candidate_value(self, value: JSONValue) -> JSONValue:
|
|
3708
|
+
"""执行内部辅助逻辑。"""
|
|
3631
3709
|
if value is None:
|
|
3632
3710
|
return None
|
|
3633
3711
|
if isinstance(value, dict):
|
|
@@ -3656,6 +3734,7 @@ class RecordTools(ToolBase):
|
|
|
3656
3734
|
*,
|
|
3657
3735
|
field_defs: list[tuple[JSONObject, FormField]],
|
|
3658
3736
|
) -> list[JSONObject]:
|
|
3737
|
+
"""执行内部辅助逻辑。"""
|
|
3659
3738
|
if not isinstance(payload, dict):
|
|
3660
3739
|
return []
|
|
3661
3740
|
rows = payload.get("list")
|
|
@@ -3731,6 +3810,7 @@ class RecordTools(ToolBase):
|
|
|
3731
3810
|
return candidates
|
|
3732
3811
|
|
|
3733
3812
|
def _relation_confirmation_candidates(self, candidates: list[JSONObject]) -> list[JSONObject]:
|
|
3813
|
+
"""执行内部辅助逻辑。"""
|
|
3734
3814
|
payloads: list[JSONObject] = []
|
|
3735
3815
|
for candidate in candidates[:LOOKUP_CONFIRMATION_CANDIDATE_LIMIT]:
|
|
3736
3816
|
payloads.append(
|
|
@@ -3753,6 +3833,7 @@ class RecordTools(ToolBase):
|
|
|
3753
3833
|
keyword: str,
|
|
3754
3834
|
state: LookupResolutionState,
|
|
3755
3835
|
) -> tuple[list[JSONObject], list[JSONObject]]:
|
|
3836
|
+
"""执行内部辅助逻辑。"""
|
|
3756
3837
|
field_defs = self._relation_search_field_defs(context, field=field, app_key=state.app_key)
|
|
3757
3838
|
searchable_fields = [item for item, _ in field_defs]
|
|
3758
3839
|
try:
|
|
@@ -3781,6 +3862,7 @@ class RecordTools(ToolBase):
|
|
|
3781
3862
|
return self._normalize_relation_candidates(result, field_defs=field_defs), searchable_fields
|
|
3782
3863
|
|
|
3783
3864
|
def _lookup_context_is_incomplete(self, state: LookupResolutionState | None) -> bool:
|
|
3865
|
+
"""执行内部辅助逻辑。"""
|
|
3784
3866
|
return bool(state is not None and not state.context_complete)
|
|
3785
3867
|
|
|
3786
3868
|
def _candidate_lookup_uses_runtime_scope(
|
|
@@ -3790,6 +3872,7 @@ class RecordTools(ToolBase):
|
|
|
3790
3872
|
workflow_node_id: int | None,
|
|
3791
3873
|
fields: JSONObject | None,
|
|
3792
3874
|
) -> bool:
|
|
3875
|
+
"""执行内部辅助逻辑。"""
|
|
3793
3876
|
return bool(
|
|
3794
3877
|
(record_id is not None and record_id > 0)
|
|
3795
3878
|
or (workflow_node_id is not None and workflow_node_id > 0)
|
|
@@ -3806,6 +3889,7 @@ class RecordTools(ToolBase):
|
|
|
3806
3889
|
workflow_node_id: int | None,
|
|
3807
3890
|
fields: JSONObject,
|
|
3808
3891
|
) -> LookupResolutionState:
|
|
3892
|
+
"""执行内部辅助逻辑。"""
|
|
3809
3893
|
index = self._get_field_index(profile, context, app_key, force_refresh=False)
|
|
3810
3894
|
apply_id = record_id if isinstance(record_id, int) and record_id > 0 else None
|
|
3811
3895
|
base_answers: list[JSONObject] = []
|
|
@@ -3851,6 +3935,7 @@ class RecordTools(ToolBase):
|
|
|
3851
3935
|
location: str,
|
|
3852
3936
|
explicit_fix_hint: str,
|
|
3853
3937
|
) -> None:
|
|
3938
|
+
"""执行内部辅助逻辑。"""
|
|
3854
3939
|
raise RecordInputError(
|
|
3855
3940
|
message=(
|
|
3856
3941
|
f"{kind} auto resolution for field '{field.que_title}' requires the current record context, "
|
|
@@ -3866,6 +3951,7 @@ class RecordTools(ToolBase):
|
|
|
3866
3951
|
)
|
|
3867
3952
|
|
|
3868
3953
|
def _normalize_backend_member_candidates(self, payload: JSONValue, *, external: bool) -> list[JSONObject]:
|
|
3954
|
+
"""执行内部辅助逻辑。"""
|
|
3869
3955
|
candidates: list[JSONObject] = []
|
|
3870
3956
|
if not isinstance(payload, dict):
|
|
3871
3957
|
return candidates
|
|
@@ -3882,6 +3968,7 @@ class RecordTools(ToolBase):
|
|
|
3882
3968
|
return candidates
|
|
3883
3969
|
|
|
3884
3970
|
def _normalize_backend_department_candidates(self, payload: JSONValue, *, external: bool) -> list[JSONObject]:
|
|
3971
|
+
"""执行内部辅助逻辑。"""
|
|
3885
3972
|
candidates: list[JSONObject] = []
|
|
3886
3973
|
if not isinstance(payload, dict):
|
|
3887
3974
|
return candidates
|
|
@@ -3900,6 +3987,7 @@ class RecordTools(ToolBase):
|
|
|
3900
3987
|
return candidates
|
|
3901
3988
|
|
|
3902
3989
|
def _department_candidate_path(self, value: JSONValue) -> str | None:
|
|
3990
|
+
"""执行内部辅助逻辑。"""
|
|
3903
3991
|
if not isinstance(value, dict):
|
|
3904
3992
|
return None
|
|
3905
3993
|
name = _normalize_optional_text(value.get("deptName", value.get("value", value.get("name"))))
|
|
@@ -3915,6 +4003,7 @@ class RecordTools(ToolBase):
|
|
|
3915
4003
|
return " / ".join(list(reversed(parent_names)) + [name])
|
|
3916
4004
|
|
|
3917
4005
|
def _rank_member_candidates(self, keyword: str, candidates: list[JSONObject]) -> list[JSONObject]:
|
|
4006
|
+
"""执行内部辅助逻辑。"""
|
|
3918
4007
|
requested = _normalize_field_lookup_key(keyword)
|
|
3919
4008
|
ranked: list[JSONObject] = []
|
|
3920
4009
|
for candidate in candidates:
|
|
@@ -3960,6 +4049,7 @@ class RecordTools(ToolBase):
|
|
|
3960
4049
|
return ranked
|
|
3961
4050
|
|
|
3962
4051
|
def _rank_department_candidates(self, keyword: str, candidates: list[JSONObject]) -> list[JSONObject]:
|
|
4052
|
+
"""执行内部辅助逻辑。"""
|
|
3963
4053
|
requested = _normalize_field_lookup_key(keyword)
|
|
3964
4054
|
ranked: list[JSONObject] = []
|
|
3965
4055
|
for candidate in candidates:
|
|
@@ -4002,6 +4092,7 @@ class RecordTools(ToolBase):
|
|
|
4002
4092
|
*,
|
|
4003
4093
|
searchable_fields: list[JSONObject],
|
|
4004
4094
|
) -> list[JSONObject]:
|
|
4095
|
+
"""执行内部辅助逻辑。"""
|
|
4005
4096
|
requested = _normalize_field_lookup_key(keyword)
|
|
4006
4097
|
primary_titles = {
|
|
4007
4098
|
_normalize_field_lookup_key(_stringify_json(item.get("title")))
|
|
@@ -4046,6 +4137,7 @@ class RecordTools(ToolBase):
|
|
|
4046
4137
|
return ranked
|
|
4047
4138
|
|
|
4048
4139
|
def _resolve_ranked_lookup_candidate(self, ranked_candidates: list[JSONObject]) -> JSONObject | None:
|
|
4140
|
+
"""执行内部辅助逻辑。"""
|
|
4049
4141
|
if not ranked_candidates:
|
|
4050
4142
|
return None
|
|
4051
4143
|
top = ranked_candidates[0]
|
|
@@ -4066,6 +4158,7 @@ class RecordTools(ToolBase):
|
|
|
4066
4158
|
method: str,
|
|
4067
4159
|
confidence: float,
|
|
4068
4160
|
) -> None:
|
|
4161
|
+
"""执行内部辅助逻辑。"""
|
|
4069
4162
|
if state is None:
|
|
4070
4163
|
return
|
|
4071
4164
|
state.resolved_fields.append(
|
|
@@ -4089,6 +4182,7 @@ class RecordTools(ToolBase):
|
|
|
4089
4182
|
parent_field: FormField | None = None,
|
|
4090
4183
|
row_ordinal: int | None = None,
|
|
4091
4184
|
) -> JSONObject:
|
|
4185
|
+
"""执行内部辅助逻辑。"""
|
|
4092
4186
|
payload: JSONObject = {
|
|
4093
4187
|
"field": field.que_title,
|
|
4094
4188
|
"kind": kind,
|
|
@@ -4112,6 +4206,7 @@ class RecordTools(ToolBase):
|
|
|
4112
4206
|
parent_field: FormField | None = None,
|
|
4113
4207
|
row_ordinal: int | None = None,
|
|
4114
4208
|
) -> None:
|
|
4209
|
+
"""执行内部辅助逻辑。"""
|
|
4115
4210
|
if state is None:
|
|
4116
4211
|
return
|
|
4117
4212
|
state.confirmation_requests.append(request)
|
|
@@ -4120,6 +4215,7 @@ class RecordTools(ToolBase):
|
|
|
4120
4215
|
state.unresolved_subtable_cells.add((parent_field.que_id, row_ordinal, field.que_id))
|
|
4121
4216
|
|
|
4122
4217
|
def _candidate_resolution_method(self, candidate: JSONObject, *, explicit_method: str | None = None) -> str:
|
|
4218
|
+
"""执行内部辅助逻辑。"""
|
|
4123
4219
|
if explicit_method:
|
|
4124
4220
|
return explicit_method
|
|
4125
4221
|
reason = _normalize_optional_text(candidate.get("match_reason")) or "resolved"
|
|
@@ -4140,6 +4236,7 @@ class RecordTools(ToolBase):
|
|
|
4140
4236
|
state: LookupResolutionState | None,
|
|
4141
4237
|
explicit_guidance: str,
|
|
4142
4238
|
) -> str:
|
|
4239
|
+
"""执行内部辅助逻辑。"""
|
|
4143
4240
|
if state is not None and self._candidate_lookup_uses_runtime_scope(
|
|
4144
4241
|
record_id=state.apply_id,
|
|
4145
4242
|
workflow_node_id=state.workflow_node_id,
|
|
@@ -4156,6 +4253,7 @@ class RecordTools(ToolBase):
|
|
|
4156
4253
|
)
|
|
4157
4254
|
|
|
4158
4255
|
def _resolve_member_candidates(self, context, field: FormField, *, keyword: str) -> list[JSONObject]: # type: ignore[no-untyped-def]
|
|
4256
|
+
"""执行内部辅助逻辑。"""
|
|
4159
4257
|
scope_type = field.member_select_scope_type
|
|
4160
4258
|
scope = field.member_select_scope if isinstance(field.member_select_scope, dict) else {}
|
|
4161
4259
|
if _scope_is_default_all(scope_type, scope, keys=("member", "depart", "role")):
|
|
@@ -4239,6 +4337,7 @@ class RecordTools(ToolBase):
|
|
|
4239
4337
|
return filtered
|
|
4240
4338
|
|
|
4241
4339
|
def _resolve_department_candidates(self, context, field: FormField, *, keyword: str) -> list[JSONObject]: # type: ignore[no-untyped-def]
|
|
4340
|
+
"""执行内部辅助逻辑。"""
|
|
4242
4341
|
scope_type = field.dept_select_scope_type
|
|
4243
4342
|
scope = field.dept_select_scope if isinstance(field.dept_select_scope, dict) else {}
|
|
4244
4343
|
if _scope_has_dynamic_or_external(scope):
|
|
@@ -4302,6 +4401,7 @@ class RecordTools(ToolBase):
|
|
|
4302
4401
|
return filtered
|
|
4303
4402
|
|
|
4304
4403
|
def _merge_member_candidate(self, merged: dict[str, JSONObject], candidate: JSONObject) -> None:
|
|
4404
|
+
"""执行内部辅助逻辑。"""
|
|
4305
4405
|
key = _member_candidate_key(candidate)
|
|
4306
4406
|
if not key:
|
|
4307
4407
|
return
|
|
@@ -4335,6 +4435,7 @@ class RecordTools(ToolBase):
|
|
|
4335
4435
|
dept_id: int,
|
|
4336
4436
|
include_sub_departments: bool,
|
|
4337
4437
|
) -> list[dict[str, Any]]:
|
|
4438
|
+
"""执行内部辅助逻辑。"""
|
|
4338
4439
|
dept_ids = {dept_id}
|
|
4339
4440
|
if include_sub_departments:
|
|
4340
4441
|
dept_ids.update(self._expand_department_ids(context, root_dept_id=dept_id))
|
|
@@ -4347,6 +4448,7 @@ class RecordTools(ToolBase):
|
|
|
4347
4448
|
return list(merged.values())
|
|
4348
4449
|
|
|
4349
4450
|
def _list_members_by_role(self, context, *, role_id: int) -> list[dict[str, Any]]: # type: ignore[no-untyped-def]
|
|
4451
|
+
"""执行内部辅助逻辑。"""
|
|
4350
4452
|
return self._fetch_internal_members(context, department_id=None, role_id=role_id)
|
|
4351
4453
|
|
|
4352
4454
|
def _list_departments_by_scope(
|
|
@@ -4356,6 +4458,7 @@ class RecordTools(ToolBase):
|
|
|
4356
4458
|
dept_id: int,
|
|
4357
4459
|
include_sub_departments: bool,
|
|
4358
4460
|
) -> list[dict[str, Any]]:
|
|
4461
|
+
"""执行内部辅助逻辑。"""
|
|
4359
4462
|
dept_ids = {dept_id}
|
|
4360
4463
|
if include_sub_departments:
|
|
4361
4464
|
dept_ids.update(self._expand_department_ids(context, root_dept_id=dept_id))
|
|
@@ -4369,6 +4472,7 @@ class RecordTools(ToolBase):
|
|
|
4369
4472
|
return list(merged.values())
|
|
4370
4473
|
|
|
4371
4474
|
def _list_all_departments(self, context) -> list[dict[str, Any]]: # type: ignore[no-untyped-def]
|
|
4475
|
+
"""执行内部辅助逻辑。"""
|
|
4372
4476
|
queue: list[int | None] = [None]
|
|
4373
4477
|
seen_ids: set[int] = set()
|
|
4374
4478
|
requested_parents: set[int | None] = set()
|
|
@@ -4401,6 +4505,7 @@ class RecordTools(ToolBase):
|
|
|
4401
4505
|
return items
|
|
4402
4506
|
|
|
4403
4507
|
def _merge_department_candidate(self, merged: dict[str, JSONObject], candidate: JSONObject) -> None:
|
|
4508
|
+
"""执行内部辅助逻辑。"""
|
|
4404
4509
|
key = _department_candidate_key(candidate)
|
|
4405
4510
|
if not key:
|
|
4406
4511
|
return
|
|
@@ -4424,6 +4529,7 @@ class RecordTools(ToolBase):
|
|
|
4424
4529
|
seen.add(marker)
|
|
4425
4530
|
|
|
4426
4531
|
def _expand_department_ids(self, context, *, root_dept_id: int) -> set[int]: # type: ignore[no-untyped-def]
|
|
4532
|
+
"""执行内部辅助逻辑。"""
|
|
4427
4533
|
seen: set[int] = set()
|
|
4428
4534
|
queue: list[int] = [root_dept_id]
|
|
4429
4535
|
while queue:
|
|
@@ -4448,6 +4554,7 @@ class RecordTools(ToolBase):
|
|
|
4448
4554
|
department_id: int | None,
|
|
4449
4555
|
role_id: int | None,
|
|
4450
4556
|
) -> list[dict[str, Any]]:
|
|
4557
|
+
"""执行内部辅助逻辑。"""
|
|
4451
4558
|
current_page = 1
|
|
4452
4559
|
fetched_pages = 0
|
|
4453
4560
|
seen: dict[str, dict[str, Any]] = {}
|
|
@@ -4483,9 +4590,11 @@ class RecordTools(ToolBase):
|
|
|
4483
4590
|
return list(seen.values())
|
|
4484
4591
|
|
|
4485
4592
|
def _search_workspace_members(self, context, *, keyword: str) -> list[dict[str, Any]]: # type: ignore[no-untyped-def]
|
|
4593
|
+
"""执行内部辅助逻辑。"""
|
|
4486
4594
|
return self._search_workspace_directory_dimension(context, dimension="MEMBER", bucket_key="member", keyword=keyword)
|
|
4487
4595
|
|
|
4488
4596
|
def _search_workspace_departments(self, context, *, keyword: str) -> list[dict[str, Any]]: # type: ignore[no-untyped-def]
|
|
4597
|
+
"""执行内部辅助逻辑。"""
|
|
4489
4598
|
return self._search_workspace_directory_dimension(context, dimension="DEPT", bucket_key="dept", keyword=keyword)
|
|
4490
4599
|
|
|
4491
4600
|
def _search_workspace_directory_dimension(
|
|
@@ -4496,6 +4605,7 @@ class RecordTools(ToolBase):
|
|
|
4496
4605
|
bucket_key: str,
|
|
4497
4606
|
keyword: str,
|
|
4498
4607
|
) -> list[dict[str, Any]]:
|
|
4608
|
+
"""执行内部辅助逻辑。"""
|
|
4499
4609
|
current_page = 1
|
|
4500
4610
|
fetched_pages = 0
|
|
4501
4611
|
seen: dict[str, dict[str, Any]] = {}
|
|
@@ -4533,6 +4643,7 @@ class RecordTools(ToolBase):
|
|
|
4533
4643
|
return list(seen.values())
|
|
4534
4644
|
|
|
4535
4645
|
def _schema_field_family(self, field: FormField) -> str:
|
|
4646
|
+
"""执行内部辅助逻辑。"""
|
|
4536
4647
|
if self._schema_is_identifier_like(field):
|
|
4537
4648
|
return "text"
|
|
4538
4649
|
que_type = field.que_type
|
|
@@ -4555,6 +4666,7 @@ class RecordTools(ToolBase):
|
|
|
4555
4666
|
return "text"
|
|
4556
4667
|
|
|
4557
4668
|
def _schema_is_identifier_like(self, field: FormField, *, field_family: str | None = None) -> bool:
|
|
4669
|
+
"""执行内部辅助逻辑。"""
|
|
4558
4670
|
normalized_title = _normalize_field_lookup_key(field.que_title)
|
|
4559
4671
|
if field.que_id == 0:
|
|
4560
4672
|
return True
|
|
@@ -4565,6 +4677,7 @@ class RecordTools(ToolBase):
|
|
|
4565
4677
|
return False
|
|
4566
4678
|
|
|
4567
4679
|
def _schema_supported_metric_ops(self, field: FormField, *, field_family: str) -> list[str]:
|
|
4680
|
+
"""执行内部辅助逻辑。"""
|
|
4568
4681
|
if field.que_type in ATTACHMENT_QUE_TYPES | RELATION_QUE_TYPES | SUBTABLE_QUE_TYPES:
|
|
4569
4682
|
return []
|
|
4570
4683
|
if self._schema_is_identifier_like(field, field_family=field_family):
|
|
@@ -4576,6 +4689,7 @@ class RecordTools(ToolBase):
|
|
|
4576
4689
|
return []
|
|
4577
4690
|
|
|
4578
4691
|
def _schema_semantic_hint(self, field: FormField, *, field_family: str) -> str:
|
|
4692
|
+
"""执行内部辅助逻辑。"""
|
|
4579
4693
|
if self._schema_is_identifier_like(field, field_family=field_family):
|
|
4580
4694
|
return "unknown"
|
|
4581
4695
|
if field_family != "number":
|
|
@@ -4590,6 +4704,7 @@ class RecordTools(ToolBase):
|
|
|
4590
4704
|
return "unknown"
|
|
4591
4705
|
|
|
4592
4706
|
def _resolve_field_by_id(self, field_id: int | None, index: FieldIndex, *, location: str) -> FormField:
|
|
4707
|
+
"""执行内部辅助逻辑。"""
|
|
4593
4708
|
if field_id is None:
|
|
4594
4709
|
raise RecordInputError(
|
|
4595
4710
|
message=f"{location} requires field_id",
|
|
@@ -4614,6 +4729,7 @@ class RecordTools(ToolBase):
|
|
|
4614
4729
|
allowed_keys: set[str],
|
|
4615
4730
|
example: str,
|
|
4616
4731
|
) -> None:
|
|
4732
|
+
"""执行内部辅助逻辑。"""
|
|
4617
4733
|
unexpected_keys = sorted(str(key) for key in item.keys() if str(key) not in allowed_keys)
|
|
4618
4734
|
if unexpected_keys:
|
|
4619
4735
|
raise RecordInputError(
|
|
@@ -4635,6 +4751,7 @@ class RecordTools(ToolBase):
|
|
|
4635
4751
|
value: JSONValue,
|
|
4636
4752
|
location: str,
|
|
4637
4753
|
) -> JSONValue:
|
|
4754
|
+
"""执行内部辅助逻辑。"""
|
|
4638
4755
|
if op in {"is_null", "not_null"}:
|
|
4639
4756
|
if value is not None:
|
|
4640
4757
|
raise RecordInputError(
|
|
@@ -4765,6 +4882,7 @@ class RecordTools(ToolBase):
|
|
|
4765
4882
|
return value
|
|
4766
4883
|
|
|
4767
4884
|
def _validate_strict_date_filter_value(self, value: JSONValue, *, location: str) -> datetime:
|
|
4885
|
+
"""执行内部辅助逻辑。"""
|
|
4768
4886
|
text = _normalize_optional_text(value)
|
|
4769
4887
|
if text is None:
|
|
4770
4888
|
raise RecordInputError(
|
|
@@ -4784,6 +4902,7 @@ class RecordTools(ToolBase):
|
|
|
4784
4902
|
return parsed
|
|
4785
4903
|
|
|
4786
4904
|
def _compile_analyze_dimensions(self, index: FieldIndex, dimensions: list[JSONObject]) -> list[JSONObject]:
|
|
4905
|
+
"""执行内部辅助逻辑。"""
|
|
4787
4906
|
supported_buckets = {None, "day", "week", "month", "quarter", "year"}
|
|
4788
4907
|
compiled: list[JSONObject] = []
|
|
4789
4908
|
used_aliases: set[str] = set()
|
|
@@ -4828,6 +4947,7 @@ class RecordTools(ToolBase):
|
|
|
4828
4947
|
return compiled
|
|
4829
4948
|
|
|
4830
4949
|
def _compile_analyze_metrics(self, index: FieldIndex, metrics: list[JSONObject]) -> list[JSONObject]:
|
|
4950
|
+
"""执行内部辅助逻辑。"""
|
|
4831
4951
|
requested_metrics = metrics or [{"op": "count", "alias": "记录数"}]
|
|
4832
4952
|
supported_ops = {"count", "sum", "avg", "min", "max", "distinct_count"}
|
|
4833
4953
|
compiled: list[JSONObject] = []
|
|
@@ -4891,6 +5011,7 @@ class RecordTools(ToolBase):
|
|
|
4891
5011
|
return compiled
|
|
4892
5012
|
|
|
4893
5013
|
def _compile_analyze_filters(self, index: FieldIndex, filters: list[JSONObject]) -> list[JSONObject]:
|
|
5014
|
+
"""执行内部辅助逻辑。"""
|
|
4894
5015
|
supported_ops = {"eq", "neq", "in", "not_in", "gt", "gte", "lt", "lte", "between", "contains", "is_null", "not_null"}
|
|
4895
5016
|
compiled: list[JSONObject] = []
|
|
4896
5017
|
for idx, item in enumerate(filters):
|
|
@@ -4925,6 +5046,7 @@ class RecordTools(ToolBase):
|
|
|
4925
5046
|
return compiled
|
|
4926
5047
|
|
|
4927
5048
|
def _compile_analyze_sort(self, sort: list[JSONObject], dimensions: list[JSONObject], metrics: list[JSONObject]) -> list[JSONObject]:
|
|
5049
|
+
"""执行内部辅助逻辑。"""
|
|
4928
5050
|
dimension_aliases = {str(item["alias"]) for item in dimensions}
|
|
4929
5051
|
metric_aliases = {str(item["alias"]) for item in metrics}
|
|
4930
5052
|
compiled: list[JSONObject] = []
|
|
@@ -4986,6 +5108,7 @@ class RecordTools(ToolBase):
|
|
|
4986
5108
|
output_profile: str,
|
|
4987
5109
|
extra_warnings: list[JSONObject] | None = None,
|
|
4988
5110
|
) -> JSONObject:
|
|
5111
|
+
"""执行内部辅助逻辑。"""
|
|
4989
5112
|
started_at = time.perf_counter()
|
|
4990
5113
|
analysis_paging = _fixed_analysis_scan_policy()
|
|
4991
5114
|
page_size = int(analysis_paging["page_size"])
|
|
@@ -5207,6 +5330,7 @@ class RecordTools(ToolBase):
|
|
|
5207
5330
|
return response
|
|
5208
5331
|
|
|
5209
5332
|
def _build_analyze_group_payload(self, answer_list: list[JSONValue], dimensions: list[JSONObject]) -> JSONObject:
|
|
5333
|
+
"""执行内部辅助逻辑。"""
|
|
5210
5334
|
if not dimensions:
|
|
5211
5335
|
return {}
|
|
5212
5336
|
payload: JSONObject = {}
|
|
@@ -5221,6 +5345,7 @@ class RecordTools(ToolBase):
|
|
|
5221
5345
|
return payload
|
|
5222
5346
|
|
|
5223
5347
|
def _initialize_metric_states(self, metrics: list[JSONObject]) -> dict[str, JSONObject]:
|
|
5348
|
+
"""执行内部辅助逻辑。"""
|
|
5224
5349
|
states: dict[str, JSONObject] = {}
|
|
5225
5350
|
for item in metrics:
|
|
5226
5351
|
states[str(item["alias"])] = {
|
|
@@ -5233,9 +5358,11 @@ class RecordTools(ToolBase):
|
|
|
5233
5358
|
return states
|
|
5234
5359
|
|
|
5235
5360
|
def _analysis_group_key(self, payload: JSONObject) -> tuple[tuple[str, object], ...]:
|
|
5361
|
+
"""执行内部辅助逻辑。"""
|
|
5236
5362
|
return tuple((key, self._freeze_group_key_value(value)) for key, value in payload.items())
|
|
5237
5363
|
|
|
5238
5364
|
def _freeze_group_key_value(self, value: JSONValue) -> object:
|
|
5365
|
+
"""执行内部辅助逻辑。"""
|
|
5239
5366
|
if isinstance(value, dict):
|
|
5240
5367
|
return tuple((key, self._freeze_group_key_value(item)) for key, item in sorted(value.items()))
|
|
5241
5368
|
if isinstance(value, list):
|
|
@@ -5243,6 +5370,7 @@ class RecordTools(ToolBase):
|
|
|
5243
5370
|
return value
|
|
5244
5371
|
|
|
5245
5372
|
def _apply_metric_states(self, states: dict[str, JSONObject], metrics: list[JSONObject], answer_list: list[JSONValue]) -> None:
|
|
5373
|
+
"""执行内部辅助逻辑。"""
|
|
5246
5374
|
for item in metrics:
|
|
5247
5375
|
alias = cast(str, item["alias"])
|
|
5248
5376
|
op = cast(str, item["op"])
|
|
@@ -5265,6 +5393,7 @@ class RecordTools(ToolBase):
|
|
|
5265
5393
|
state["max"] = amount if state["max"] is None else max(float(state["max"]), amount)
|
|
5266
5394
|
|
|
5267
5395
|
def _render_metric_values(self, states: dict[str, JSONObject], metrics: list[JSONObject]) -> JSONObject:
|
|
5396
|
+
"""执行内部辅助逻辑。"""
|
|
5268
5397
|
rendered: JSONObject = {}
|
|
5269
5398
|
for item in metrics:
|
|
5270
5399
|
alias = cast(str, item["alias"])
|
|
@@ -5287,6 +5416,7 @@ class RecordTools(ToolBase):
|
|
|
5287
5416
|
return rendered
|
|
5288
5417
|
|
|
5289
5418
|
def _matches_analyze_filters(self, answer_list: list[JSONValue], filters: list[JSONObject]) -> bool:
|
|
5419
|
+
"""执行内部辅助逻辑。"""
|
|
5290
5420
|
for item in filters:
|
|
5291
5421
|
field = cast(FormField, item["field"])
|
|
5292
5422
|
if not _match_analyze_filter(_extract_field_value(answer_list, field), cast(str, item["op"]), item.get("value")):
|
|
@@ -5300,6 +5430,7 @@ class RecordTools(ToolBase):
|
|
|
5300
5430
|
dimensions: list[JSONObject],
|
|
5301
5431
|
metrics: list[JSONObject],
|
|
5302
5432
|
) -> list[JSONObject]:
|
|
5433
|
+
"""执行内部辅助逻辑。"""
|
|
5303
5434
|
if not rows or not sort:
|
|
5304
5435
|
if dimensions and any(item.get("bucket") for item in dimensions):
|
|
5305
5436
|
return sorted(rows, key=lambda item: json.dumps(item.get("dimensions", {}), ensure_ascii=False, sort_keys=True))
|
|
@@ -5324,6 +5455,7 @@ class RecordTools(ToolBase):
|
|
|
5324
5455
|
rows_truncated: bool,
|
|
5325
5456
|
extra_warnings: list[JSONObject],
|
|
5326
5457
|
) -> list[JSONObject]:
|
|
5458
|
+
"""执行内部辅助逻辑。"""
|
|
5327
5459
|
warnings: list[JSONObject] = []
|
|
5328
5460
|
warnings.extend(extra_warnings)
|
|
5329
5461
|
if local_filtering:
|
|
@@ -5347,6 +5479,7 @@ class RecordTools(ToolBase):
|
|
|
5347
5479
|
view_key: str | None,
|
|
5348
5480
|
view_name: str | None,
|
|
5349
5481
|
) -> JSONObject:
|
|
5482
|
+
"""执行内部辅助逻辑。"""
|
|
5350
5483
|
if not app_key:
|
|
5351
5484
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
5352
5485
|
|
|
@@ -5410,6 +5543,7 @@ class RecordTools(ToolBase):
|
|
|
5410
5543
|
existing_answers_override: list[JSONObject] | None = None,
|
|
5411
5544
|
field_index_override: FieldIndex | None = None,
|
|
5412
5545
|
) -> JSONObject:
|
|
5546
|
+
"""执行内部辅助逻辑。"""
|
|
5413
5547
|
schema = self._get_form_schema(profile, context, app_key, force_refresh=force_refresh_form)
|
|
5414
5548
|
base_index = field_index_override or _build_applicant_top_level_field_index(schema)
|
|
5415
5549
|
question_relations = _collect_question_relations(schema)
|
|
@@ -5727,6 +5861,7 @@ class RecordTools(ToolBase):
|
|
|
5727
5861
|
app_key: str,
|
|
5728
5862
|
apply_id: int,
|
|
5729
5863
|
) -> list[JSONObject]:
|
|
5864
|
+
"""执行内部辅助逻辑。"""
|
|
5730
5865
|
record = self.backend.request(
|
|
5731
5866
|
"GET",
|
|
5732
5867
|
context,
|
|
@@ -5744,6 +5879,7 @@ class RecordTools(ToolBase):
|
|
|
5744
5879
|
selector_index: FieldIndex,
|
|
5745
5880
|
visible_question_ids: set[int],
|
|
5746
5881
|
) -> list[JSONObject]:
|
|
5882
|
+
"""执行内部辅助逻辑。"""
|
|
5747
5883
|
invalid_fields: list[JSONObject] = []
|
|
5748
5884
|
if not visible_question_ids:
|
|
5749
5885
|
return invalid_fields
|
|
@@ -5787,6 +5923,7 @@ class RecordTools(ToolBase):
|
|
|
5787
5923
|
full_index: FieldIndex,
|
|
5788
5924
|
skip_cells: set[tuple[int, int, int]] | None = None,
|
|
5789
5925
|
) -> list[JSONObject]:
|
|
5926
|
+
"""执行内部辅助逻辑。"""
|
|
5790
5927
|
missing_required_fields: list[JSONObject] = []
|
|
5791
5928
|
skipped = skip_cells or set()
|
|
5792
5929
|
answers_by_field_id = {
|
|
@@ -5884,6 +6021,7 @@ class RecordTools(ToolBase):
|
|
|
5884
6021
|
existing_answers: list[JSONObject],
|
|
5885
6022
|
patch_answers: list[JSONObject],
|
|
5886
6023
|
) -> list[JSONObject]:
|
|
6024
|
+
"""执行内部辅助逻辑。"""
|
|
5887
6025
|
merged_by_id: dict[int, JSONObject] = {}
|
|
5888
6026
|
order: list[int] = []
|
|
5889
6027
|
for source in (existing_answers, patch_answers):
|
|
@@ -5896,6 +6034,7 @@ class RecordTools(ToolBase):
|
|
|
5896
6034
|
merged_by_id[que_id] = item
|
|
5897
6035
|
return [merged_by_id[que_id] for que_id in order]
|
|
5898
6036
|
|
|
6037
|
+
@tool_cn_name("查询记录")
|
|
5899
6038
|
def record_query(
|
|
5900
6039
|
self,
|
|
5901
6040
|
*,
|
|
@@ -5923,6 +6062,7 @@ class RecordTools(ToolBase):
|
|
|
5923
6062
|
view_key: str | None = None,
|
|
5924
6063
|
view_name: str | None = None,
|
|
5925
6064
|
) -> JSONObject:
|
|
6065
|
+
"""执行记录相关逻辑。"""
|
|
5926
6066
|
resolved_mode = _resolve_query_mode(query_mode, apply_id=apply_id, amount_column=amount_column, time_range=time_range, stat_policy=stat_policy)
|
|
5927
6067
|
if resolved_mode == "summary":
|
|
5928
6068
|
raise_tool_error(
|
|
@@ -5972,6 +6112,7 @@ class RecordTools(ToolBase):
|
|
|
5972
6112
|
view_name=view_name,
|
|
5973
6113
|
)
|
|
5974
6114
|
|
|
6115
|
+
@tool_cn_name("创建记录")
|
|
5975
6116
|
def record_create(
|
|
5976
6117
|
self,
|
|
5977
6118
|
*,
|
|
@@ -5983,6 +6124,7 @@ class RecordTools(ToolBase):
|
|
|
5983
6124
|
verify_write: bool = False,
|
|
5984
6125
|
force_refresh_form: bool = False,
|
|
5985
6126
|
) -> JSONObject:
|
|
6127
|
+
"""执行记录相关逻辑。"""
|
|
5986
6128
|
if submit_type not in (0, 1):
|
|
5987
6129
|
raise_tool_error(QingflowApiError.config_error("submit_type must be 0 or 1"))
|
|
5988
6130
|
|
|
@@ -6030,6 +6172,7 @@ class RecordTools(ToolBase):
|
|
|
6030
6172
|
# listType 降级顺序(内部 record_get)
|
|
6031
6173
|
_INTERNAL_GET_LIST_TYPE_FALLBACKS = [DEFAULT_RECORD_LIST_TYPE, 14, 1, 2, 12]
|
|
6032
6174
|
|
|
6175
|
+
@tool_cn_name("获取记录")
|
|
6033
6176
|
def record_get(
|
|
6034
6177
|
self,
|
|
6035
6178
|
*,
|
|
@@ -6040,6 +6183,7 @@ class RecordTools(ToolBase):
|
|
|
6040
6183
|
list_type: int | None,
|
|
6041
6184
|
audit_node_id: int | None,
|
|
6042
6185
|
) -> JSONObject:
|
|
6186
|
+
"""执行记录相关逻辑。"""
|
|
6043
6187
|
normalized_apply_id = self._validate_app_and_record(app_key, apply_id)
|
|
6044
6188
|
|
|
6045
6189
|
def runner(session_profile, context):
|
|
@@ -6088,6 +6232,7 @@ class RecordTools(ToolBase):
|
|
|
6088
6232
|
|
|
6089
6233
|
return self._run_record_tool(profile, runner)
|
|
6090
6234
|
|
|
6235
|
+
@tool_cn_name("搜索记录")
|
|
6091
6236
|
def record_search(
|
|
6092
6237
|
self,
|
|
6093
6238
|
*,
|
|
@@ -6103,6 +6248,7 @@ class RecordTools(ToolBase):
|
|
|
6103
6248
|
view_key: str | None = None,
|
|
6104
6249
|
view_name: str | None = None,
|
|
6105
6250
|
) -> JSONObject:
|
|
6251
|
+
"""执行记录相关逻辑。"""
|
|
6106
6252
|
if not app_key:
|
|
6107
6253
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
6108
6254
|
|
|
@@ -6165,6 +6311,7 @@ class RecordTools(ToolBase):
|
|
|
6165
6311
|
|
|
6166
6312
|
return self._run_record_tool(profile, runner)
|
|
6167
6313
|
|
|
6314
|
+
@tool_cn_name("修改记录")
|
|
6168
6315
|
def record_update(
|
|
6169
6316
|
self,
|
|
6170
6317
|
*,
|
|
@@ -6177,6 +6324,7 @@ class RecordTools(ToolBase):
|
|
|
6177
6324
|
verify_write: bool = False,
|
|
6178
6325
|
force_refresh_form: bool = False,
|
|
6179
6326
|
) -> JSONObject:
|
|
6327
|
+
"""执行记录相关逻辑。"""
|
|
6180
6328
|
normalized_apply_id = self._validate_app_and_record(app_key, apply_id)
|
|
6181
6329
|
|
|
6182
6330
|
def runner(session_profile, context):
|
|
@@ -6227,7 +6375,9 @@ class RecordTools(ToolBase):
|
|
|
6227
6375
|
|
|
6228
6376
|
return self._run_record_tool(profile, runner)
|
|
6229
6377
|
|
|
6378
|
+
@tool_cn_name("删除记录(兼容)")
|
|
6230
6379
|
def record_delete(self, *, profile: str, app_key: str, apply_id: int, list_type: int) -> JSONObject:
|
|
6380
|
+
"""执行记录相关逻辑。"""
|
|
6231
6381
|
normalized_apply_id = self._validate_app_and_record(app_key, apply_id)
|
|
6232
6382
|
|
|
6233
6383
|
def runner(session_profile, context):
|
|
@@ -6263,6 +6413,7 @@ class RecordTools(ToolBase):
|
|
|
6263
6413
|
output_profile: str,
|
|
6264
6414
|
list_type: int,
|
|
6265
6415
|
) -> JSONObject:
|
|
6416
|
+
"""执行内部辅助逻辑。"""
|
|
6266
6417
|
if not app_key:
|
|
6267
6418
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
6268
6419
|
if apply_id is None or apply_id <= 0:
|
|
@@ -6362,6 +6513,7 @@ class RecordTools(ToolBase):
|
|
|
6362
6513
|
view_key: str | None = None,
|
|
6363
6514
|
view_name: str | None = None,
|
|
6364
6515
|
) -> JSONObject:
|
|
6516
|
+
"""执行内部辅助逻辑。"""
|
|
6365
6517
|
if not app_key:
|
|
6366
6518
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
6367
6519
|
if not select_columns:
|
|
@@ -6624,6 +6776,7 @@ class RecordTools(ToolBase):
|
|
|
6624
6776
|
return self._run_record_tool(profile, runner)
|
|
6625
6777
|
|
|
6626
6778
|
def _get_form_schema(self, profile: str, context, app_key: str, *, force_refresh: bool) -> JSONObject: # type: ignore[no-untyped-def]
|
|
6779
|
+
"""执行内部辅助逻辑。"""
|
|
6627
6780
|
cache_key = (profile, app_key, "applicant_node", None)
|
|
6628
6781
|
if not force_refresh and cache_key in self._form_cache:
|
|
6629
6782
|
return self._form_cache[cache_key]
|
|
@@ -6638,6 +6791,7 @@ class RecordTools(ToolBase):
|
|
|
6638
6791
|
return normalized
|
|
6639
6792
|
|
|
6640
6793
|
def _get_field_index(self, profile: str, context, app_key: str, *, force_refresh: bool) -> FieldIndex: # type: ignore[no-untyped-def]
|
|
6794
|
+
"""执行内部辅助逻辑。"""
|
|
6641
6795
|
return _build_field_index(self._get_form_schema(profile, context, app_key, force_refresh=force_refresh))
|
|
6642
6796
|
|
|
6643
6797
|
def _get_applicant_top_level_field_index(
|
|
@@ -6648,11 +6802,13 @@ class RecordTools(ToolBase):
|
|
|
6648
6802
|
*,
|
|
6649
6803
|
force_refresh: bool,
|
|
6650
6804
|
) -> FieldIndex:
|
|
6805
|
+
"""执行内部辅助逻辑。"""
|
|
6651
6806
|
return _build_applicant_top_level_field_index(
|
|
6652
6807
|
self._get_form_schema(profile, context, app_key, force_refresh=force_refresh)
|
|
6653
6808
|
)
|
|
6654
6809
|
|
|
6655
6810
|
def _resolve_applicant_node(self, profile: str, context, app_key: str, *, force_refresh: bool) -> WorkflowNodeRef: # type: ignore[no-untyped-def]
|
|
6811
|
+
"""执行内部辅助逻辑。"""
|
|
6656
6812
|
cache_key = (profile, app_key)
|
|
6657
6813
|
if not force_refresh and cache_key in self._applicant_node_cache:
|
|
6658
6814
|
return self._applicant_node_cache[cache_key]
|
|
@@ -6673,6 +6829,7 @@ class RecordTools(ToolBase):
|
|
|
6673
6829
|
return applicant_node
|
|
6674
6830
|
|
|
6675
6831
|
def _get_view_list(self, profile: str, context, app_key: str) -> list[JSONObject]: # type: ignore[no-untyped-def]
|
|
6832
|
+
"""执行内部辅助逻辑。"""
|
|
6676
6833
|
cache_key = (profile, app_key)
|
|
6677
6834
|
if cache_key in self._view_list_cache:
|
|
6678
6835
|
return self._view_list_cache[cache_key]
|
|
@@ -6682,6 +6839,7 @@ class RecordTools(ToolBase):
|
|
|
6682
6839
|
return normalized
|
|
6683
6840
|
|
|
6684
6841
|
def _get_view_form_schema(self, profile: str, context, view_key: str, *, force_refresh: bool) -> JSONObject: # type: ignore[no-untyped-def]
|
|
6842
|
+
"""执行内部辅助逻辑。"""
|
|
6685
6843
|
cache_key = (profile, f"view:{view_key}", "browse_view", None)
|
|
6686
6844
|
if not force_refresh and cache_key in self._form_cache:
|
|
6687
6845
|
return self._form_cache[cache_key]
|
|
@@ -6698,6 +6856,7 @@ class RecordTools(ToolBase):
|
|
|
6698
6856
|
*,
|
|
6699
6857
|
force_refresh: bool = False,
|
|
6700
6858
|
) -> JSONObject | None:
|
|
6859
|
+
"""执行内部辅助逻辑。"""
|
|
6701
6860
|
cache_key = (profile, view_key)
|
|
6702
6861
|
if not force_refresh and cache_key in self._view_config_cache:
|
|
6703
6862
|
return self._view_config_cache[cache_key]
|
|
@@ -6730,6 +6889,7 @@ class RecordTools(ToolBase):
|
|
|
6730
6889
|
resolved_view: AccessibleViewRoute | None = None,
|
|
6731
6890
|
clear_view_caches: bool = False,
|
|
6732
6891
|
) -> None:
|
|
6892
|
+
"""执行内部辅助逻辑。"""
|
|
6733
6893
|
view_key = (
|
|
6734
6894
|
resolved_view.view_selection.view_key
|
|
6735
6895
|
if resolved_view is not None and resolved_view.view_selection is not None
|
|
@@ -6756,10 +6916,12 @@ class RecordTools(ToolBase):
|
|
|
6756
6916
|
self._view_config_cache.pop(cache_key, None)
|
|
6757
6917
|
|
|
6758
6918
|
def _record_preflight_used_force_refresh(self, raw_preflight: JSONObject) -> bool:
|
|
6919
|
+
"""执行内部辅助逻辑。"""
|
|
6759
6920
|
data = raw_preflight.get("data")
|
|
6760
6921
|
return bool(isinstance(data, dict) and data.get("schema_force_refreshed"))
|
|
6761
6922
|
|
|
6762
6923
|
def _record_preflight_suggests_stale_schema(self, plan_data: JSONObject) -> bool:
|
|
6924
|
+
"""执行内部辅助逻辑。"""
|
|
6763
6925
|
validation = plan_data.get("validation")
|
|
6764
6926
|
invalid_fields = validation.get("invalid_fields") if isinstance(validation, dict) else None
|
|
6765
6927
|
if not isinstance(invalid_fields, list):
|
|
@@ -6767,6 +6929,7 @@ class RecordTools(ToolBase):
|
|
|
6767
6929
|
return any(self._field_error_suggests_stale_schema(entry) for entry in invalid_fields if isinstance(entry, dict))
|
|
6768
6930
|
|
|
6769
6931
|
def _field_error_suggests_stale_schema(self, entry: JSONObject) -> bool:
|
|
6932
|
+
"""执行内部辅助逻辑。"""
|
|
6770
6933
|
error_code = _normalize_optional_text(entry.get("error_code"))
|
|
6771
6934
|
if error_code == "VIEW_SCOPE_FIELD_HIDDEN":
|
|
6772
6935
|
return False
|
|
@@ -6786,6 +6949,7 @@ class RecordTools(ToolBase):
|
|
|
6786
6949
|
record: JSONObject,
|
|
6787
6950
|
normalized_record: JSONObject,
|
|
6788
6951
|
) -> bool:
|
|
6952
|
+
"""执行内部辅助逻辑。"""
|
|
6789
6953
|
for field in selected_fields:
|
|
6790
6954
|
if field.que_type not in SUBTABLE_QUE_TYPES:
|
|
6791
6955
|
continue
|
|
@@ -6809,6 +6973,7 @@ class RecordTools(ToolBase):
|
|
|
6809
6973
|
list_type: int,
|
|
6810
6974
|
force_refresh: bool,
|
|
6811
6975
|
) -> JSONObject:
|
|
6976
|
+
"""执行内部辅助逻辑。"""
|
|
6812
6977
|
cache_key = (profile, app_key, "browse_system", list_type)
|
|
6813
6978
|
if not force_refresh and cache_key in self._form_cache:
|
|
6814
6979
|
return self._form_cache[cache_key]
|
|
@@ -6825,6 +6990,7 @@ class RecordTools(ToolBase):
|
|
|
6825
6990
|
return normalized
|
|
6826
6991
|
|
|
6827
6992
|
def _get_view_field_index(self, profile: str, context, view_key: str, *, force_refresh: bool) -> FieldIndex: # type: ignore[no-untyped-def]
|
|
6993
|
+
"""执行内部辅助逻辑。"""
|
|
6828
6994
|
return _build_field_index(self._get_view_form_schema(profile, context, view_key, force_refresh=force_refresh))
|
|
6829
6995
|
|
|
6830
6996
|
def _get_system_browse_field_index(
|
|
@@ -6836,6 +7002,7 @@ class RecordTools(ToolBase):
|
|
|
6836
7002
|
list_type: int,
|
|
6837
7003
|
force_refresh: bool,
|
|
6838
7004
|
) -> FieldIndex:
|
|
7005
|
+
"""执行内部辅助逻辑。"""
|
|
6839
7006
|
return _build_field_index(
|
|
6840
7007
|
self._get_system_browse_schema(
|
|
6841
7008
|
profile,
|
|
@@ -6855,6 +7022,7 @@ class RecordTools(ToolBase):
|
|
|
6855
7022
|
*,
|
|
6856
7023
|
force_refresh: bool,
|
|
6857
7024
|
) -> FieldIndex:
|
|
7025
|
+
"""执行内部辅助逻辑。"""
|
|
6858
7026
|
return self._build_browse_write_scope(
|
|
6859
7027
|
profile,
|
|
6860
7028
|
context,
|
|
@@ -6872,6 +7040,7 @@ class RecordTools(ToolBase):
|
|
|
6872
7040
|
*,
|
|
6873
7041
|
force_refresh: bool,
|
|
6874
7042
|
) -> JSONObject:
|
|
7043
|
+
"""执行内部辅助逻辑。"""
|
|
6875
7044
|
applicant_index: FieldIndex | None
|
|
6876
7045
|
applicant_writable_field_ids: set[int]
|
|
6877
7046
|
try:
|
|
@@ -6969,6 +7138,7 @@ class RecordTools(ToolBase):
|
|
|
6969
7138
|
app_key: str,
|
|
6970
7139
|
resolved_view: AccessibleViewRoute,
|
|
6971
7140
|
) -> list[int]:
|
|
7141
|
+
"""执行内部辅助逻辑。"""
|
|
6972
7142
|
def runner(_session_profile, context):
|
|
6973
7143
|
return self._derive_public_list_columns(profile, context, app_key, resolved_view)
|
|
6974
7144
|
|
|
@@ -6981,6 +7151,7 @@ class RecordTools(ToolBase):
|
|
|
6981
7151
|
app_key: str,
|
|
6982
7152
|
resolved_view: AccessibleViewRoute,
|
|
6983
7153
|
) -> list[int]:
|
|
7154
|
+
"""执行内部辅助逻辑。"""
|
|
6984
7155
|
browse_scope = self._build_browse_write_scope(
|
|
6985
7156
|
profile,
|
|
6986
7157
|
context,
|
|
@@ -7018,6 +7189,7 @@ class RecordTools(ToolBase):
|
|
|
7018
7189
|
return field_ids
|
|
7019
7190
|
|
|
7020
7191
|
def _get_view_question_ids(self, profile: str, context, view_key: str) -> set[int]: # type: ignore[no-untyped-def]
|
|
7192
|
+
"""执行内部辅助逻辑。"""
|
|
7021
7193
|
try:
|
|
7022
7194
|
payload = self.backend.request("GET", context, f"/view/{view_key}/question")
|
|
7023
7195
|
except QingflowApiError as exc:
|
|
@@ -7045,6 +7217,7 @@ class RecordTools(ToolBase):
|
|
|
7045
7217
|
schema_mode: str,
|
|
7046
7218
|
resolved_view: AccessibleViewRoute | None,
|
|
7047
7219
|
) -> list[FormField]:
|
|
7220
|
+
"""执行内部辅助逻辑。"""
|
|
7048
7221
|
return list(index.by_id.values())
|
|
7049
7222
|
|
|
7050
7223
|
def _probe_list_type_access(
|
|
@@ -7054,6 +7227,7 @@ class RecordTools(ToolBase):
|
|
|
7054
7227
|
app_key: str,
|
|
7055
7228
|
list_type: int,
|
|
7056
7229
|
) -> bool:
|
|
7230
|
+
"""执行内部辅助逻辑。"""
|
|
7057
7231
|
try:
|
|
7058
7232
|
self.backend.request(
|
|
7059
7233
|
"POST",
|
|
@@ -7078,6 +7252,7 @@ class RecordTools(ToolBase):
|
|
|
7078
7252
|
view_name: str | None,
|
|
7079
7253
|
allow_default: bool,
|
|
7080
7254
|
) -> tuple[AccessibleViewRoute, list[JSONObject]]:
|
|
7255
|
+
"""执行内部辅助逻辑。"""
|
|
7081
7256
|
def runner(_session_profile, context):
|
|
7082
7257
|
return self._resolve_accessible_view_route(
|
|
7083
7258
|
profile,
|
|
@@ -7104,6 +7279,7 @@ class RecordTools(ToolBase):
|
|
|
7104
7279
|
view_name: str | None,
|
|
7105
7280
|
allow_default: bool,
|
|
7106
7281
|
) -> tuple[AccessibleViewRoute, list[JSONObject]]:
|
|
7282
|
+
"""执行内部辅助逻辑。"""
|
|
7107
7283
|
warnings: list[JSONObject] = []
|
|
7108
7284
|
normalized_view_id = _normalize_optional_text(view_id)
|
|
7109
7285
|
if normalized_view_id:
|
|
@@ -7209,6 +7385,7 @@ class RecordTools(ToolBase):
|
|
|
7209
7385
|
view_key: str | None,
|
|
7210
7386
|
view_name: str | None,
|
|
7211
7387
|
) -> ViewSelection | None:
|
|
7388
|
+
"""执行内部辅助逻辑。"""
|
|
7212
7389
|
requested_key = _normalize_optional_text(view_key)
|
|
7213
7390
|
requested_name = _normalize_optional_text(view_name)
|
|
7214
7391
|
if requested_key is None and requested_name is None:
|
|
@@ -7253,6 +7430,7 @@ class RecordTools(ToolBase):
|
|
|
7253
7430
|
)
|
|
7254
7431
|
|
|
7255
7432
|
def _get_department_member_ids(self, context, dept_id: int) -> set[int]: # type: ignore[no-untyped-def]
|
|
7433
|
+
"""执行内部辅助逻辑。"""
|
|
7256
7434
|
page_num = 1
|
|
7257
7435
|
page_size = 200
|
|
7258
7436
|
member_ids: set[int] = set()
|
|
@@ -7288,6 +7466,7 @@ class RecordTools(ToolBase):
|
|
|
7288
7466
|
view_selection: ViewSelection | None,
|
|
7289
7467
|
dept_member_cache: dict[int, set[int]],
|
|
7290
7468
|
) -> bool:
|
|
7469
|
+
"""执行内部辅助逻辑。"""
|
|
7291
7470
|
if view_selection is None or not view_selection.conditions:
|
|
7292
7471
|
return True
|
|
7293
7472
|
for group in view_selection.conditions:
|
|
@@ -7312,6 +7491,7 @@ class RecordTools(ToolBase):
|
|
|
7312
7491
|
arguments: JSONObject,
|
|
7313
7492
|
view_selection: ViewSelection | None,
|
|
7314
7493
|
) -> JSONObject:
|
|
7494
|
+
"""执行内部辅助逻辑。"""
|
|
7315
7495
|
routed_mode = _resolve_query_mode(
|
|
7316
7496
|
str(arguments.get("query_mode", "auto")),
|
|
7317
7497
|
apply_id=_coerce_count(arguments.get("apply_id")),
|
|
@@ -7376,6 +7556,7 @@ class RecordTools(ToolBase):
|
|
|
7376
7556
|
search_que_ids: list[int] | None,
|
|
7377
7557
|
list_type: int,
|
|
7378
7558
|
) -> JSONObject:
|
|
7559
|
+
"""执行内部辅助逻辑。"""
|
|
7379
7560
|
if view_selection is not None and _is_board_view_type(view_selection.view_type):
|
|
7380
7561
|
return self._search_board_view_page(
|
|
7381
7562
|
context,
|
|
@@ -7406,6 +7587,7 @@ class RecordTools(ToolBase):
|
|
|
7406
7587
|
return result if isinstance(result, dict) else {}
|
|
7407
7588
|
|
|
7408
7589
|
def _should_retry_list_type_fallback(self, error: QingflowApiError) -> bool:
|
|
7590
|
+
"""执行内部辅助逻辑。"""
|
|
7409
7591
|
if error.backend_code in {40002, 40027, 404}:
|
|
7410
7592
|
return True
|
|
7411
7593
|
if error.http_status in {404, 500}:
|
|
@@ -7424,6 +7606,7 @@ class RecordTools(ToolBase):
|
|
|
7424
7606
|
list_type: int,
|
|
7425
7607
|
include_list_type: bool,
|
|
7426
7608
|
) -> JSONObject:
|
|
7609
|
+
"""执行内部辅助逻辑。"""
|
|
7427
7610
|
body: JSONObject = {"pageNum": page_num, "pageSize": page_size}
|
|
7428
7611
|
if include_list_type:
|
|
7429
7612
|
body["type"] = list_type
|
|
@@ -7453,6 +7636,7 @@ class RecordTools(ToolBase):
|
|
|
7453
7636
|
return body
|
|
7454
7637
|
|
|
7455
7638
|
def _get_board_lane_ids(self, context, *, view_key: str) -> list[int]: # type: ignore[no-untyped-def]
|
|
7639
|
+
"""执行内部辅助逻辑。"""
|
|
7456
7640
|
payload = self.backend.request(
|
|
7457
7641
|
"GET",
|
|
7458
7642
|
context,
|
|
@@ -7485,6 +7669,7 @@ class RecordTools(ToolBase):
|
|
|
7485
7669
|
offset: int,
|
|
7486
7670
|
limit: int,
|
|
7487
7671
|
) -> list[JSONObject]:
|
|
7672
|
+
"""执行内部辅助逻辑。"""
|
|
7488
7673
|
if limit <= 0:
|
|
7489
7674
|
return []
|
|
7490
7675
|
request_page_size = max(_coerce_count(filter_payload.get("pageSize")) or 1, 1)
|
|
@@ -7532,6 +7717,7 @@ class RecordTools(ToolBase):
|
|
|
7532
7717
|
sorts: list[JSONObject],
|
|
7533
7718
|
search_que_ids: list[int] | None,
|
|
7534
7719
|
) -> JSONObject:
|
|
7720
|
+
"""执行内部辅助逻辑。"""
|
|
7535
7721
|
filter_payload = self._build_view_filter_payload(
|
|
7536
7722
|
page_num=page_num,
|
|
7537
7723
|
page_size=page_size,
|
|
@@ -7628,6 +7814,7 @@ class RecordTools(ToolBase):
|
|
|
7628
7814
|
resolution_state: LookupResolutionState | None = None,
|
|
7629
7815
|
field_index_override: FieldIndex | None = None,
|
|
7630
7816
|
) -> list[JSONObject]:
|
|
7817
|
+
"""执行内部辅助逻辑。"""
|
|
7631
7818
|
if not app_key:
|
|
7632
7819
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
7633
7820
|
if not answers and not fields:
|
|
@@ -7674,6 +7861,7 @@ class RecordTools(ToolBase):
|
|
|
7674
7861
|
*,
|
|
7675
7862
|
resolution_state: LookupResolutionState | None = None,
|
|
7676
7863
|
) -> JSONObject | None: # type: ignore[no-untyped-def]
|
|
7864
|
+
"""执行内部辅助逻辑。"""
|
|
7677
7865
|
field = self._resolve_field_from_answer_item(item, index)
|
|
7678
7866
|
if field.que_type in SUBTABLE_QUE_TYPES:
|
|
7679
7867
|
table_values_input: JSONValue = item.get("tableValues")
|
|
@@ -7747,6 +7935,7 @@ class RecordTools(ToolBase):
|
|
|
7747
7935
|
*,
|
|
7748
7936
|
resolution_state: LookupResolutionState | None = None,
|
|
7749
7937
|
) -> JSONObject | None: # type: ignore[no-untyped-def]
|
|
7938
|
+
"""执行内部辅助逻辑。"""
|
|
7750
7939
|
field = self._resolve_field_selector(field_selector, index, location="fields")
|
|
7751
7940
|
if field.que_type in SUBTABLE_QUE_TYPES:
|
|
7752
7941
|
return {
|
|
@@ -7802,6 +7991,7 @@ class RecordTools(ToolBase):
|
|
|
7802
7991
|
parent_field: FormField | None = None,
|
|
7803
7992
|
row_ordinal: int | None = None,
|
|
7804
7993
|
) -> JSONObject | None:
|
|
7994
|
+
"""执行内部辅助逻辑。"""
|
|
7805
7995
|
values: list[JSONObject] = []
|
|
7806
7996
|
refer_values: list[JSONObject] = []
|
|
7807
7997
|
for raw_value in _expand_values(raw_values):
|
|
@@ -7830,6 +8020,7 @@ class RecordTools(ToolBase):
|
|
|
7830
8020
|
}
|
|
7831
8021
|
|
|
7832
8022
|
def _raise_if_verify_unsupported_write_field(self, field: FormField, raw_value: JSONValue, *, location: str) -> None:
|
|
8023
|
+
"""执行内部辅助逻辑。"""
|
|
7833
8024
|
if field.que_type not in VERIFY_UNSUPPORTED_WRITE_QUE_TYPES:
|
|
7834
8025
|
return
|
|
7835
8026
|
raise RecordInputError(
|
|
@@ -7854,6 +8045,7 @@ class RecordTools(ToolBase):
|
|
|
7854
8045
|
resolution_state: LookupResolutionState | None = None,
|
|
7855
8046
|
location: str = "field",
|
|
7856
8047
|
) -> list[JSONObject]:
|
|
8048
|
+
"""执行内部辅助逻辑。"""
|
|
7857
8049
|
if field.que_type in SINGLE_SELECT_QUE_TYPES:
|
|
7858
8050
|
return [_option_value(raw_values[0], field)]
|
|
7859
8051
|
if field.que_type in MULTI_SELECT_QUE_TYPES:
|
|
@@ -7906,6 +8098,7 @@ class RecordTools(ToolBase):
|
|
|
7906
8098
|
location: str,
|
|
7907
8099
|
resolution_state: LookupResolutionState | None = None,
|
|
7908
8100
|
) -> list[list[JSONObject]]:
|
|
8101
|
+
"""执行内部辅助逻辑。"""
|
|
7909
8102
|
row_values = raw_rows
|
|
7910
8103
|
if isinstance(raw_rows, dict):
|
|
7911
8104
|
if "rows" in raw_rows:
|
|
@@ -7950,6 +8143,7 @@ class RecordTools(ToolBase):
|
|
|
7950
8143
|
location: str,
|
|
7951
8144
|
resolution_state: LookupResolutionState | None = None,
|
|
7952
8145
|
) -> list[JSONObject]:
|
|
8146
|
+
"""执行内部辅助逻辑。"""
|
|
7953
8147
|
row_id: int | None = None
|
|
7954
8148
|
normalized_cells: list[JSONObject] = []
|
|
7955
8149
|
if isinstance(row, dict):
|
|
@@ -8068,6 +8262,7 @@ class RecordTools(ToolBase):
|
|
|
8068
8262
|
parent_field: FormField | None = None,
|
|
8069
8263
|
row_ordinal: int | None = None,
|
|
8070
8264
|
) -> JSONObject | None:
|
|
8265
|
+
"""执行内部辅助逻辑。"""
|
|
8071
8266
|
field = self._resolve_field_from_answer_item(item, subtable_index)
|
|
8072
8267
|
if field.que_type in SUBTABLE_QUE_TYPES:
|
|
8073
8268
|
raise RecordInputError(
|
|
@@ -8132,6 +8327,7 @@ class RecordTools(ToolBase):
|
|
|
8132
8327
|
parent_field: FormField | None = None,
|
|
8133
8328
|
row_ordinal: int | None = None,
|
|
8134
8329
|
) -> JSONObject | None:
|
|
8330
|
+
"""执行内部辅助逻辑。"""
|
|
8135
8331
|
field = self._resolve_field_selector(field_selector, subtable_index, location=location)
|
|
8136
8332
|
if field.que_type in SUBTABLE_QUE_TYPES:
|
|
8137
8333
|
raise RecordInputError(
|
|
@@ -8171,6 +8367,7 @@ class RecordTools(ToolBase):
|
|
|
8171
8367
|
}
|
|
8172
8368
|
|
|
8173
8369
|
def _subtable_field_index(self, table_field: FormField) -> FieldIndex:
|
|
8370
|
+
"""执行内部辅助逻辑。"""
|
|
8174
8371
|
raw = table_field.raw if isinstance(table_field.raw, dict) else {}
|
|
8175
8372
|
schema: JSONObject = {}
|
|
8176
8373
|
if isinstance(raw.get("subQuestions"), list):
|
|
@@ -8188,6 +8385,7 @@ class RecordTools(ToolBase):
|
|
|
8188
8385
|
return index
|
|
8189
8386
|
|
|
8190
8387
|
def _subtable_field_index_optional(self, table_field: FormField | None) -> FieldIndex | None:
|
|
8388
|
+
"""执行内部辅助逻辑。"""
|
|
8191
8389
|
if table_field is None:
|
|
8192
8390
|
return None
|
|
8193
8391
|
try:
|
|
@@ -8196,6 +8394,7 @@ class RecordTools(ToolBase):
|
|
|
8196
8394
|
return None
|
|
8197
8395
|
|
|
8198
8396
|
def _run_record_tool(self, profile: str, func, *, require_workspace: bool = True): # type: ignore[no-untyped-def]
|
|
8397
|
+
"""执行内部辅助逻辑。"""
|
|
8199
8398
|
try:
|
|
8200
8399
|
return self._run(profile, func, require_workspace=require_workspace)
|
|
8201
8400
|
except RecordInputError as error:
|
|
@@ -8213,6 +8412,7 @@ class RecordTools(ToolBase):
|
|
|
8213
8412
|
)
|
|
8214
8413
|
|
|
8215
8414
|
def _request_route_payload(self, context) -> JSONObject: # type: ignore[no-untyped-def]
|
|
8415
|
+
"""执行内部辅助逻辑。"""
|
|
8216
8416
|
describe_route = getattr(self.backend, "describe_route", None)
|
|
8217
8417
|
if callable(describe_route):
|
|
8218
8418
|
payload = describe_route(context)
|
|
@@ -8225,6 +8425,7 @@ class RecordTools(ToolBase):
|
|
|
8225
8425
|
}
|
|
8226
8426
|
|
|
8227
8427
|
def _normalize_public_output_profile(self, output_profile: str, *, allow_normalized: bool = False) -> str:
|
|
8428
|
+
"""执行内部辅助逻辑。"""
|
|
8228
8429
|
normalized = (output_profile or "normal").strip().lower()
|
|
8229
8430
|
allowed = {"normal", "verbose"}
|
|
8230
8431
|
if allow_normalized:
|
|
@@ -8235,6 +8436,7 @@ class RecordTools(ToolBase):
|
|
|
8235
8436
|
return normalized
|
|
8236
8437
|
|
|
8237
8438
|
def _normalize_record_list_where(self, where: list[JSONObject]) -> list[JSONObject]:
|
|
8439
|
+
"""执行内部辅助逻辑。"""
|
|
8238
8440
|
normalized: list[JSONObject] = []
|
|
8239
8441
|
for idx, item in enumerate(where):
|
|
8240
8442
|
if not isinstance(item, dict):
|
|
@@ -8260,6 +8462,7 @@ class RecordTools(ToolBase):
|
|
|
8260
8462
|
return normalized
|
|
8261
8463
|
|
|
8262
8464
|
def _normalize_record_list_order_by(self, order_by: list[JSONObject]) -> list[JSONObject]:
|
|
8465
|
+
"""执行内部辅助逻辑。"""
|
|
8263
8466
|
normalized: list[JSONObject] = []
|
|
8264
8467
|
for idx, item in enumerate(order_by):
|
|
8265
8468
|
if not isinstance(item, dict):
|
|
@@ -8280,6 +8483,7 @@ class RecordTools(ToolBase):
|
|
|
8280
8483
|
return normalized
|
|
8281
8484
|
|
|
8282
8485
|
def _normalize_record_write_submit_type(self, submit_type: str | int) -> int:
|
|
8486
|
+
"""执行内部辅助逻辑。"""
|
|
8283
8487
|
if isinstance(submit_type, int):
|
|
8284
8488
|
if submit_type in {0, 1}:
|
|
8285
8489
|
return submit_type
|
|
@@ -8292,6 +8496,7 @@ class RecordTools(ToolBase):
|
|
|
8292
8496
|
raise_tool_error(QingflowApiError.config_error("submit_type must be save or submit"))
|
|
8293
8497
|
|
|
8294
8498
|
def _normalize_record_write_clauses(self, clauses: list[JSONObject], *, location: str) -> list[JSONObject]:
|
|
8499
|
+
"""执行内部辅助逻辑。"""
|
|
8295
8500
|
normalized: list[JSONObject] = []
|
|
8296
8501
|
for idx, item in enumerate(clauses):
|
|
8297
8502
|
if not isinstance(item, dict):
|
|
@@ -8319,6 +8524,7 @@ class RecordTools(ToolBase):
|
|
|
8319
8524
|
submit_type: int,
|
|
8320
8525
|
selection: JSONObject | None = None,
|
|
8321
8526
|
) -> JSONObject:
|
|
8527
|
+
"""执行内部辅助逻辑。"""
|
|
8322
8528
|
payload: JSONObject = {
|
|
8323
8529
|
"operation": operation,
|
|
8324
8530
|
"record_id": record_id,
|
|
@@ -8337,6 +8543,7 @@ class RecordTools(ToolBase):
|
|
|
8337
8543
|
fields: JSONObject,
|
|
8338
8544
|
selector_index: FieldIndex,
|
|
8339
8545
|
) -> tuple[list[JSONObject], JSONObject]:
|
|
8546
|
+
"""执行内部辅助逻辑。"""
|
|
8340
8547
|
canonical_answers: list[JSONObject] = []
|
|
8341
8548
|
for item in answers:
|
|
8342
8549
|
if not isinstance(item, dict):
|
|
@@ -8358,6 +8565,7 @@ class RecordTools(ToolBase):
|
|
|
8358
8565
|
return canonical_answers, canonical_fields
|
|
8359
8566
|
|
|
8360
8567
|
def _record_write_human_review_payload(self, operation: str, *, enabled: bool) -> JSONObject | None:
|
|
8568
|
+
"""执行内部辅助逻辑。"""
|
|
8361
8569
|
if not enabled:
|
|
8362
8570
|
return None
|
|
8363
8571
|
return {
|
|
@@ -8375,6 +8583,7 @@ class RecordTools(ToolBase):
|
|
|
8375
8583
|
record_id: int | None,
|
|
8376
8584
|
selection: JSONObject | None,
|
|
8377
8585
|
) -> None:
|
|
8586
|
+
"""执行内部辅助逻辑。"""
|
|
8378
8587
|
if exc.backend_code != 40002:
|
|
8379
8588
|
raise exc
|
|
8380
8589
|
raise_tool_error(
|
|
@@ -8409,6 +8618,7 @@ class RecordTools(ToolBase):
|
|
|
8409
8618
|
human_review: bool,
|
|
8410
8619
|
target_resource: JSONObject,
|
|
8411
8620
|
) -> JSONObject:
|
|
8621
|
+
"""执行内部辅助逻辑。"""
|
|
8412
8622
|
plan_data = cast(JSONObject, raw_preflight.get("data", {}))
|
|
8413
8623
|
validation = cast(JSONObject, plan_data.get("validation", {}))
|
|
8414
8624
|
field_errors = self._record_write_public_field_errors(plan_data)
|
|
@@ -8454,6 +8664,7 @@ class RecordTools(ToolBase):
|
|
|
8454
8664
|
human_review: bool,
|
|
8455
8665
|
target_resource: JSONObject,
|
|
8456
8666
|
) -> JSONObject:
|
|
8667
|
+
"""执行内部辅助逻辑。"""
|
|
8457
8668
|
plan_data = cast(JSONObject, raw_preflight.get("data", {}))
|
|
8458
8669
|
validation = cast(JSONObject, plan_data.get("validation", {}))
|
|
8459
8670
|
resolved_fields = cast(list[JSONObject], plan_data.get("lookup_resolved_fields", []))
|
|
@@ -8496,6 +8707,7 @@ class RecordTools(ToolBase):
|
|
|
8496
8707
|
human_review: bool,
|
|
8497
8708
|
preflight: JSONObject | None,
|
|
8498
8709
|
) -> JSONObject:
|
|
8710
|
+
"""执行内部辅助逻辑。"""
|
|
8499
8711
|
preflight_data = cast(JSONObject, preflight.get("data", {})) if isinstance(preflight, dict) else {}
|
|
8500
8712
|
validation = cast(JSONObject, preflight_data.get("validation", {}))
|
|
8501
8713
|
warnings_payload = validation.get("warnings", [])
|
|
@@ -8547,6 +8759,7 @@ class RecordTools(ToolBase):
|
|
|
8547
8759
|
output_profile: str,
|
|
8548
8760
|
human_review: bool,
|
|
8549
8761
|
) -> JSONObject:
|
|
8762
|
+
"""执行内部辅助逻辑。"""
|
|
8550
8763
|
error_payload: JSONObject = {
|
|
8551
8764
|
"error_code": "RECORD_WRITE_EXECUTION_FAILED",
|
|
8552
8765
|
"message": str(exc),
|
|
@@ -8598,6 +8811,7 @@ class RecordTools(ToolBase):
|
|
|
8598
8811
|
return response
|
|
8599
8812
|
|
|
8600
8813
|
def _record_write_public_field_errors(self, plan_data: JSONObject) -> list[JSONObject]:
|
|
8814
|
+
"""执行内部辅助逻辑。"""
|
|
8601
8815
|
existing = plan_data.get("field_errors")
|
|
8602
8816
|
if isinstance(existing, list):
|
|
8603
8817
|
return [cast(JSONObject, item) for item in existing if isinstance(item, dict)]
|
|
@@ -8618,6 +8832,7 @@ class RecordTools(ToolBase):
|
|
|
8618
8832
|
missing_required_fields: list[JSONObject],
|
|
8619
8833
|
readonly_or_system_fields: list[JSONObject],
|
|
8620
8834
|
) -> list[JSONObject]:
|
|
8835
|
+
"""执行内部辅助逻辑。"""
|
|
8621
8836
|
errors: list[JSONObject] = []
|
|
8622
8837
|
for item in invalid_fields:
|
|
8623
8838
|
payload: JSONObject = {
|
|
@@ -8686,6 +8901,7 @@ class RecordTools(ToolBase):
|
|
|
8686
8901
|
return errors
|
|
8687
8902
|
|
|
8688
8903
|
def _record_delete_many(self, *, profile: str, app_key: str, record_ids: list[int]) -> JSONObject:
|
|
8904
|
+
"""执行内部辅助逻辑。"""
|
|
8689
8905
|
if not app_key:
|
|
8690
8906
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
8691
8907
|
normalized_ids = [item for item in record_ids if isinstance(item, int) and item > 0]
|
|
@@ -8711,6 +8927,7 @@ class RecordTools(ToolBase):
|
|
|
8711
8927
|
return self._run_record_tool(profile, runner)
|
|
8712
8928
|
|
|
8713
8929
|
def _resolve_field_selector(self, selector: str | int | None, index: FieldIndex, *, location: str) -> FormField:
|
|
8930
|
+
"""执行内部辅助逻辑。"""
|
|
8714
8931
|
if selector is None:
|
|
8715
8932
|
raise RecordInputError(
|
|
8716
8933
|
message=f"{location} requires a field selector",
|
|
@@ -8796,6 +9013,7 @@ class RecordTools(ToolBase):
|
|
|
8796
9013
|
matches: list[SubtableLeafRef],
|
|
8797
9014
|
matched_via: str,
|
|
8798
9015
|
) -> RecordInputError:
|
|
9016
|
+
"""执行内部辅助逻辑。"""
|
|
8799
9017
|
if len(matches) > 1:
|
|
8800
9018
|
return RecordInputError(
|
|
8801
9019
|
message=f"{location} field '{requested}' matches subtable leaf fields under multiple parent tables",
|
|
@@ -8840,6 +9058,7 @@ class RecordTools(ToolBase):
|
|
|
8840
9058
|
)
|
|
8841
9059
|
|
|
8842
9060
|
def _resolve_field_from_answer_item(self, item: JSONObject, index: FieldIndex) -> FormField:
|
|
9061
|
+
"""执行内部辅助逻辑。"""
|
|
8843
9062
|
for key in ("queId", "que_id", "queTitle", "que_title", "field_id", "fieldId"):
|
|
8844
9063
|
if key in item:
|
|
8845
9064
|
return self._resolve_field_selector(cast(str | int, item[key]), index, location="answers")
|
|
@@ -8857,6 +9076,7 @@ class RecordTools(ToolBase):
|
|
|
8857
9076
|
max_columns: int | None,
|
|
8858
9077
|
default_limit: int,
|
|
8859
9078
|
) -> list[FormField]:
|
|
9079
|
+
"""执行内部辅助逻辑。"""
|
|
8860
9080
|
if not selectors:
|
|
8861
9081
|
raise_tool_error(QingflowApiError.config_error("select_columns is required"))
|
|
8862
9082
|
limit = _bounded_column_limit(max_columns, default_limit=default_limit, hard_limit=default_limit)
|
|
@@ -8881,6 +9101,7 @@ class RecordTools(ToolBase):
|
|
|
8881
9101
|
*,
|
|
8882
9102
|
max_columns: int | None,
|
|
8883
9103
|
) -> list[FormField]:
|
|
9104
|
+
"""执行内部辅助逻辑。"""
|
|
8884
9105
|
if selectors:
|
|
8885
9106
|
return self._resolve_select_columns(
|
|
8886
9107
|
selectors,
|
|
@@ -8904,6 +9125,7 @@ class RecordTools(ToolBase):
|
|
|
8904
9125
|
return candidates[:limit]
|
|
8905
9126
|
|
|
8906
9127
|
def _resolve_match_rules(self, context, filters: list[JSONObject], index: FieldIndex) -> list[JSONObject]: # type: ignore[no-untyped-def]
|
|
9128
|
+
"""执行内部辅助逻辑。"""
|
|
8907
9129
|
rules: list[JSONObject] = []
|
|
8908
9130
|
for item in filters:
|
|
8909
9131
|
if not isinstance(item, dict):
|
|
@@ -8972,6 +9194,7 @@ class RecordTools(ToolBase):
|
|
|
8972
9194
|
return rules
|
|
8973
9195
|
|
|
8974
9196
|
def _build_department_filter_rule(self, context, field: FormField, item: JSONObject) -> JSONObject | None: # type: ignore[no-untyped-def]
|
|
9197
|
+
"""执行内部辅助逻辑。"""
|
|
8975
9198
|
raw_value: JSONValue | None = None
|
|
8976
9199
|
for key in ("search_options", "searchOptions", "search_keys", "searchKeys", "search_key", "searchKey", "value", "values"):
|
|
8977
9200
|
if key in item:
|
|
@@ -8986,6 +9209,7 @@ class RecordTools(ToolBase):
|
|
|
8986
9209
|
return _department_filter_rule(field.que_id, field.que_type, details, judge_type=judge_type)
|
|
8987
9210
|
|
|
8988
9211
|
def _resolve_department_filter_details(self, context, raw_value: JSONValue) -> list[JSONObject]: # type: ignore[no-untyped-def]
|
|
9212
|
+
"""执行内部辅助逻辑。"""
|
|
8989
9213
|
values = raw_value if isinstance(raw_value, list) else [raw_value]
|
|
8990
9214
|
details: list[JSONObject] = []
|
|
8991
9215
|
seen: set[int] = set()
|
|
@@ -8999,6 +9223,7 @@ class RecordTools(ToolBase):
|
|
|
8999
9223
|
return details
|
|
9000
9224
|
|
|
9001
9225
|
def _resolve_department_filter_detail(self, context, raw_value: JSONValue) -> JSONObject: # type: ignore[no-untyped-def]
|
|
9226
|
+
"""执行内部辅助逻辑。"""
|
|
9002
9227
|
if isinstance(raw_value, dict):
|
|
9003
9228
|
dept_id = _coerce_count(raw_value.get("id", raw_value.get("deptId")))
|
|
9004
9229
|
if dept_id is not None:
|
|
@@ -9029,9 +9254,11 @@ class RecordTools(ToolBase):
|
|
|
9029
9254
|
return self._lookup_department_filter_detail(context, keyword)
|
|
9030
9255
|
|
|
9031
9256
|
def _lookup_department_filter_detail(self, context, keyword: str) -> JSONObject: # type: ignore[no-untyped-def]
|
|
9257
|
+
"""执行内部辅助逻辑。"""
|
|
9032
9258
|
return self._lookup_department_detail(context, keyword, purpose="filter")
|
|
9033
9259
|
|
|
9034
9260
|
def _candidate_lookup_sample(self, candidates: list[JSONObject], *, kind: str) -> list[JSONObject]:
|
|
9261
|
+
"""执行内部辅助逻辑。"""
|
|
9035
9262
|
sample: list[JSONObject] = []
|
|
9036
9263
|
for item in candidates[:10]:
|
|
9037
9264
|
if kind == "relation":
|
|
@@ -9066,6 +9293,7 @@ class RecordTools(ToolBase):
|
|
|
9066
9293
|
value: JSONValue,
|
|
9067
9294
|
error: QingflowApiError,
|
|
9068
9295
|
) -> None:
|
|
9296
|
+
"""执行内部辅助逻辑。"""
|
|
9069
9297
|
field_kind = "member" if kind == "member" else "department"
|
|
9070
9298
|
raise RecordInputError(
|
|
9071
9299
|
message=f"{field_kind} candidates for field '{field.que_title}' could not be loaded",
|
|
@@ -9088,6 +9316,7 @@ class RecordTools(ToolBase):
|
|
|
9088
9316
|
text_keys: tuple[str, ...],
|
|
9089
9317
|
fallback_id_keys: tuple[str, ...] = (),
|
|
9090
9318
|
) -> str:
|
|
9319
|
+
"""执行内部辅助逻辑。"""
|
|
9091
9320
|
if isinstance(value, dict):
|
|
9092
9321
|
for key in text_keys:
|
|
9093
9322
|
text = _normalize_optional_text(value.get(key))
|
|
@@ -9111,6 +9340,7 @@ class RecordTools(ToolBase):
|
|
|
9111
9340
|
keyword: str,
|
|
9112
9341
|
state: LookupResolutionState,
|
|
9113
9342
|
) -> list[JSONObject]:
|
|
9343
|
+
"""执行内部辅助逻辑。"""
|
|
9114
9344
|
scope = field.member_select_scope if isinstance(field.member_select_scope, dict) else {}
|
|
9115
9345
|
use_external = bool(
|
|
9116
9346
|
isinstance(scope.get("externalMemberList"), list) and scope.get("externalMemberList")
|
|
@@ -9132,6 +9362,7 @@ class RecordTools(ToolBase):
|
|
|
9132
9362
|
return self._normalize_backend_member_candidates(result, external=use_external)
|
|
9133
9363
|
|
|
9134
9364
|
def _member_confirmation_candidates(self, candidates: list[JSONObject]) -> list[JSONObject]:
|
|
9365
|
+
"""执行内部辅助逻辑。"""
|
|
9135
9366
|
payloads: list[JSONObject] = []
|
|
9136
9367
|
for candidate in candidates[:LOOKUP_CONFIRMATION_CANDIDATE_LIMIT]:
|
|
9137
9368
|
source_labels = []
|
|
@@ -9169,6 +9400,7 @@ class RecordTools(ToolBase):
|
|
|
9169
9400
|
resolution_state: LookupResolutionState | None = None,
|
|
9170
9401
|
location: str,
|
|
9171
9402
|
) -> JSONObject | None: # type: ignore[no-untyped-def]
|
|
9403
|
+
"""执行内部辅助逻辑。"""
|
|
9172
9404
|
explicit_member_id: int | None = None
|
|
9173
9405
|
explicit_user_id: str | None = None
|
|
9174
9406
|
explicit_email: str | None = None
|
|
@@ -9298,6 +9530,7 @@ class RecordTools(ToolBase):
|
|
|
9298
9530
|
return None
|
|
9299
9531
|
|
|
9300
9532
|
def _match_member_candidates(self, candidates: list[JSONObject], value: JSONValue) -> list[JSONObject]:
|
|
9533
|
+
"""执行内部辅助逻辑。"""
|
|
9301
9534
|
member_id: int | None = None
|
|
9302
9535
|
user_id: str | None = None
|
|
9303
9536
|
email: str | None = None
|
|
@@ -9339,6 +9572,7 @@ class RecordTools(ToolBase):
|
|
|
9339
9572
|
return matches
|
|
9340
9573
|
|
|
9341
9574
|
def _lookup_department_detail(self, context, keyword: str, *, purpose: str) -> JSONObject: # type: ignore[no-untyped-def]
|
|
9575
|
+
"""执行内部辅助逻辑。"""
|
|
9342
9576
|
payload = self.backend.request(
|
|
9343
9577
|
"GET",
|
|
9344
9578
|
context,
|
|
@@ -9372,6 +9606,7 @@ class RecordTools(ToolBase):
|
|
|
9372
9606
|
return {"id": dept_id, "value": _stringify_json(matched.get("deptName", matched.get("value", matched.get("name", dept_id))))}
|
|
9373
9607
|
|
|
9374
9608
|
def _match_department_candidates(self, candidates: list[JSONObject], value: JSONValue) -> list[JSONObject]:
|
|
9609
|
+
"""执行内部辅助逻辑。"""
|
|
9375
9610
|
dept_id: int | None = None
|
|
9376
9611
|
display: str | None = None
|
|
9377
9612
|
if isinstance(value, dict):
|
|
@@ -9401,6 +9636,7 @@ class RecordTools(ToolBase):
|
|
|
9401
9636
|
keyword: str,
|
|
9402
9637
|
state: LookupResolutionState,
|
|
9403
9638
|
) -> list[JSONObject]:
|
|
9639
|
+
"""执行内部辅助逻辑。"""
|
|
9404
9640
|
scope = field.dept_select_scope if isinstance(field.dept_select_scope, dict) else {}
|
|
9405
9641
|
external = bool(
|
|
9406
9642
|
isinstance(scope.get("externalDepartList"), list) and scope.get("externalDepartList")
|
|
@@ -9411,6 +9647,7 @@ class RecordTools(ToolBase):
|
|
|
9411
9647
|
return self._normalize_backend_department_candidates(result, external=external)
|
|
9412
9648
|
|
|
9413
9649
|
def _department_confirmation_candidates(self, candidates: list[JSONObject]) -> list[JSONObject]:
|
|
9650
|
+
"""执行内部辅助逻辑。"""
|
|
9414
9651
|
payloads: list[JSONObject] = []
|
|
9415
9652
|
for candidate in candidates[:LOOKUP_CONFIRMATION_CANDIDATE_LIMIT]:
|
|
9416
9653
|
payloads.append(
|
|
@@ -9435,6 +9672,7 @@ class RecordTools(ToolBase):
|
|
|
9435
9672
|
resolution_state: LookupResolutionState | None = None,
|
|
9436
9673
|
location: str,
|
|
9437
9674
|
) -> JSONObject | None: # type: ignore[no-untyped-def]
|
|
9675
|
+
"""执行内部辅助逻辑。"""
|
|
9438
9676
|
explicit_dept_id: int | None = None
|
|
9439
9677
|
explicit_label: str | None = None
|
|
9440
9678
|
if isinstance(value, dict):
|
|
@@ -9577,6 +9815,7 @@ class RecordTools(ToolBase):
|
|
|
9577
9815
|
parent_field: FormField | None = None,
|
|
9578
9816
|
row_ordinal: int | None = None,
|
|
9579
9817
|
) -> tuple[JSONObject | None, JSONObject | None]:
|
|
9818
|
+
"""执行内部辅助逻辑。"""
|
|
9580
9819
|
explicit_apply_id: str | None = None
|
|
9581
9820
|
keyword: str | None = None
|
|
9582
9821
|
if isinstance(value, dict):
|
|
@@ -9707,6 +9946,7 @@ class RecordTools(ToolBase):
|
|
|
9707
9946
|
return None, None
|
|
9708
9947
|
|
|
9709
9948
|
def _resolve_filter_field_entries(self, filters: list[JSONObject], index: FieldIndex) -> list[JSONObject]:
|
|
9949
|
+
"""执行内部辅助逻辑。"""
|
|
9710
9950
|
entries: list[JSONObject] = []
|
|
9711
9951
|
for item in filters:
|
|
9712
9952
|
if not isinstance(item, dict):
|
|
@@ -9719,6 +9959,7 @@ class RecordTools(ToolBase):
|
|
|
9719
9959
|
return entries
|
|
9720
9960
|
|
|
9721
9961
|
def _resolve_sorts(self, sorts: list[JSONObject], index: FieldIndex) -> list[JSONObject]:
|
|
9962
|
+
"""执行内部辅助逻辑。"""
|
|
9722
9963
|
resolved: list[JSONObject] = []
|
|
9723
9964
|
for item in sorts:
|
|
9724
9965
|
if not isinstance(item, dict):
|
|
@@ -9732,6 +9973,7 @@ class RecordTools(ToolBase):
|
|
|
9732
9973
|
return resolved
|
|
9733
9974
|
|
|
9734
9975
|
def _resolve_time_range_column(self, time_range: JSONObject, index: FieldIndex) -> FormField | None:
|
|
9976
|
+
"""执行内部辅助逻辑。"""
|
|
9735
9977
|
if not time_range or not isinstance(time_range, dict):
|
|
9736
9978
|
return None
|
|
9737
9979
|
column = time_range.get("column")
|
|
@@ -9740,6 +9982,7 @@ class RecordTools(ToolBase):
|
|
|
9740
9982
|
return self._resolve_field_selector(cast(str | int, column), index, location="time_range.column")
|
|
9741
9983
|
|
|
9742
9984
|
def _build_time_range_filter(self, time_range: JSONObject, field: FormField) -> JSONObject | None:
|
|
9985
|
+
"""执行内部辅助逻辑。"""
|
|
9743
9986
|
if not time_range:
|
|
9744
9987
|
return None
|
|
9745
9988
|
value_from = time_range.get("from")
|
|
@@ -9761,6 +10004,7 @@ class RecordTools(ToolBase):
|
|
|
9761
10004
|
time_range: JSONObject,
|
|
9762
10005
|
field: FormField | None,
|
|
9763
10006
|
) -> list[JSONObject]:
|
|
10007
|
+
"""执行内部辅助逻辑。"""
|
|
9764
10008
|
if field is None:
|
|
9765
10009
|
return match_rules
|
|
9766
10010
|
time_rule = self._build_time_range_filter(time_range, field)
|
|
@@ -9776,6 +10020,7 @@ class RecordTools(ToolBase):
|
|
|
9776
10020
|
return [*match_rules, time_rule]
|
|
9777
10021
|
|
|
9778
10022
|
def _collect_write_plan_field_refs(self, *, fields: JSONObject, answers: list[JSONObject], index: FieldIndex) -> list[JSONObject]:
|
|
10023
|
+
"""执行内部辅助逻辑。"""
|
|
9779
10024
|
refs: list[JSONObject] = []
|
|
9780
10025
|
for field_key in fields.keys():
|
|
9781
10026
|
refs.append(self._resolve_write_plan_field_ref("fields", field_key, index))
|
|
@@ -9792,6 +10037,7 @@ class RecordTools(ToolBase):
|
|
|
9792
10037
|
return refs
|
|
9793
10038
|
|
|
9794
10039
|
def _resolve_write_plan_field_ref(self, source: str, requested: str, index: FieldIndex) -> JSONObject:
|
|
10040
|
+
"""执行内部辅助逻辑。"""
|
|
9795
10041
|
try:
|
|
9796
10042
|
field = self._resolve_field_selector(requested, index, location=source)
|
|
9797
10043
|
return {
|
|
@@ -9823,6 +10069,7 @@ class RecordTools(ToolBase):
|
|
|
9823
10069
|
}
|
|
9824
10070
|
|
|
9825
10071
|
def _validate_app_and_record(self, app_key: str, apply_id: int | str) -> int:
|
|
10072
|
+
"""执行内部辅助逻辑。"""
|
|
9826
10073
|
if not app_key:
|
|
9827
10074
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
9828
10075
|
normalized_apply_id = _coerce_count(apply_id)
|
|
@@ -9831,6 +10078,7 @@ class RecordTools(ToolBase):
|
|
|
9831
10078
|
return normalized_apply_id
|
|
9832
10079
|
|
|
9833
10080
|
def _validate_record_write(self, app_key: str, answers: list[JSONObject], apply_id: int | None = None) -> None:
|
|
10081
|
+
"""执行内部辅助逻辑。"""
|
|
9834
10082
|
if not app_key:
|
|
9835
10083
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
9836
10084
|
if apply_id is not None and apply_id <= 0:
|
|
@@ -9848,6 +10096,7 @@ class RecordTools(ToolBase):
|
|
|
9848
10096
|
index: FieldIndex,
|
|
9849
10097
|
verify_list_type: int = DEFAULT_RECORD_LIST_TYPE,
|
|
9850
10098
|
) -> JSONObject:
|
|
10099
|
+
"""执行内部辅助逻辑。"""
|
|
9851
10100
|
if apply_id is None:
|
|
9852
10101
|
return {
|
|
9853
10102
|
"verified": False,
|
|
@@ -9942,6 +10191,7 @@ class RecordTools(ToolBase):
|
|
|
9942
10191
|
apply_id: int,
|
|
9943
10192
|
original_error: QingflowApiError,
|
|
9944
10193
|
) -> JSONObject:
|
|
10194
|
+
"""执行内部辅助逻辑。"""
|
|
9945
10195
|
for page_num in range(1, VERIFY_TASK_FALLBACK_MAX_PAGES + 1):
|
|
9946
10196
|
task_page = self.backend.request(
|
|
9947
10197
|
"POST",
|
|
@@ -10013,6 +10263,7 @@ class RecordTools(ToolBase):
|
|
|
10013
10263
|
empty_fields: list[JSONObject],
|
|
10014
10264
|
count_mismatches: list[JSONObject],
|
|
10015
10265
|
) -> None:
|
|
10266
|
+
"""执行内部辅助逻辑。"""
|
|
10016
10267
|
field_payload = _field_ref_payload(field) if field is not None else {"que_id": None}
|
|
10017
10268
|
if not actual_rows:
|
|
10018
10269
|
empty_fields.append(field_payload)
|
|
@@ -10090,6 +10341,7 @@ class RecordTools(ToolBase):
|
|
|
10090
10341
|
)
|
|
10091
10342
|
|
|
10092
10343
|
def _score_field_matches(self, requested: str, index: FieldIndex, *, fuzzy: bool, top_k: int) -> list[JSONObject]:
|
|
10344
|
+
"""执行内部辅助逻辑。"""
|
|
10093
10345
|
requested_text = requested.strip()
|
|
10094
10346
|
requested_key = _normalize_field_lookup_key(requested_text)
|
|
10095
10347
|
if not requested_key:
|
|
@@ -10126,6 +10378,7 @@ class RecordTools(ToolBase):
|
|
|
10126
10378
|
return matches[: max(top_k, 1)]
|
|
10127
10379
|
|
|
10128
10380
|
def _raise_need_more_data(self, completeness: JSONObject, evidence: JSONObject, message: str) -> None:
|
|
10381
|
+
"""执行内部辅助逻辑。"""
|
|
10129
10382
|
raise RuntimeError(
|
|
10130
10383
|
json.dumps(
|
|
10131
10384
|
{
|