@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
|
@@ -12,7 +12,7 @@ from ..config import DEFAULT_PROFILE
|
|
|
12
12
|
from ..errors import QingflowApiError, raise_tool_error
|
|
13
13
|
from ..json_types import JSONObject
|
|
14
14
|
from .approval_tools import ApprovalTools, _approval_page_amount, _approval_page_items, _approval_page_total
|
|
15
|
-
from .base import ToolBase
|
|
15
|
+
from .base import ToolBase, tool_cn_name
|
|
16
16
|
from .qingbi_report_tools import _qingbi_base_url
|
|
17
17
|
from .record_tools import (
|
|
18
18
|
FieldIndex,
|
|
@@ -38,13 +38,24 @@ from .task_tools import TaskTools, _task_page_amount, _task_page_items, _task_pa
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
class TaskContextTools(ToolBase):
|
|
41
|
+
"""任务上下文工具(中文名:任务上下文与审批执行)。
|
|
42
|
+
|
|
43
|
+
类型:任务深度上下文工具。
|
|
44
|
+
主要职责:
|
|
45
|
+
1. 聚合任务详情、候选人、关联报表与流程日志;
|
|
46
|
+
2. 执行审批动作(通过、驳回、转交等);
|
|
47
|
+
3. 为任务处理过程提供可执行上下文而非仅列表数据。
|
|
48
|
+
"""
|
|
49
|
+
|
|
41
50
|
def __init__(self, sessions, backend) -> None: # type: ignore[no-untyped-def]
|
|
51
|
+
"""执行内部辅助逻辑。"""
|
|
42
52
|
super().__init__(sessions, backend)
|
|
43
53
|
self._task_tools = TaskTools(sessions, backend)
|
|
44
54
|
self._approval_tools = ApprovalTools(sessions, backend)
|
|
45
55
|
self._record_tools = RecordTools(sessions, backend)
|
|
46
56
|
|
|
47
57
|
def register(self, mcp: FastMCP) -> None:
|
|
58
|
+
"""注册当前工具到 MCP 服务。"""
|
|
48
59
|
@mcp.tool(
|
|
49
60
|
description=(
|
|
50
61
|
"List workflow tasks. `query` first uses backend task search; if the backend returns zero rows, "
|
|
@@ -144,6 +155,7 @@ class TaskContextTools(ToolBase):
|
|
|
144
155
|
workflow_node_id=workflow_node_id,
|
|
145
156
|
)
|
|
146
157
|
|
|
158
|
+
@tool_cn_name("任务上下文列表")
|
|
147
159
|
def task_list(
|
|
148
160
|
self,
|
|
149
161
|
*,
|
|
@@ -156,6 +168,7 @@ class TaskContextTools(ToolBase):
|
|
|
156
168
|
page: int,
|
|
157
169
|
page_size: int,
|
|
158
170
|
) -> dict[str, Any]:
|
|
171
|
+
"""执行任务相关逻辑。"""
|
|
159
172
|
normalized_type = self._task_tools._task_box_to_type(task_box)
|
|
160
173
|
normalized_status = self._task_tools._flow_status_to_process_status(flow_status)
|
|
161
174
|
raw = self._task_tools.task_list(
|
|
@@ -230,6 +243,7 @@ class TaskContextTools(ToolBase):
|
|
|
230
243
|
},
|
|
231
244
|
}
|
|
232
245
|
|
|
246
|
+
@tool_cn_name("任务上下文详情")
|
|
233
247
|
def task_get(
|
|
234
248
|
self,
|
|
235
249
|
*,
|
|
@@ -240,6 +254,7 @@ class TaskContextTools(ToolBase):
|
|
|
240
254
|
include_candidates: bool,
|
|
241
255
|
include_associated_reports: bool,
|
|
242
256
|
) -> dict[str, Any]:
|
|
257
|
+
"""执行任务相关逻辑。"""
|
|
243
258
|
self._require_app_record_and_node(app_key, record_id, workflow_node_id)
|
|
244
259
|
|
|
245
260
|
def runner(session_profile, context):
|
|
@@ -266,6 +281,7 @@ class TaskContextTools(ToolBase):
|
|
|
266
281
|
|
|
267
282
|
return self._run(profile, runner)
|
|
268
283
|
|
|
284
|
+
@tool_cn_name("任务仅保存")
|
|
269
285
|
def task_save_only(
|
|
270
286
|
self,
|
|
271
287
|
*,
|
|
@@ -275,6 +291,7 @@ class TaskContextTools(ToolBase):
|
|
|
275
291
|
workflow_node_id: int,
|
|
276
292
|
fields: dict[str, Any] | None = None,
|
|
277
293
|
) -> dict[str, Any]:
|
|
294
|
+
"""执行任务相关逻辑。"""
|
|
278
295
|
field_updates = dict(fields or {})
|
|
279
296
|
if not field_updates:
|
|
280
297
|
raise_tool_error(QingflowApiError.config_error("fields is required and must be non-empty for task_save_only"))
|
|
@@ -288,6 +305,7 @@ class TaskContextTools(ToolBase):
|
|
|
288
305
|
fields=field_updates,
|
|
289
306
|
)
|
|
290
307
|
|
|
308
|
+
@tool_cn_name("执行任务动作")
|
|
291
309
|
def task_action_execute(
|
|
292
310
|
self,
|
|
293
311
|
*,
|
|
@@ -299,6 +317,7 @@ class TaskContextTools(ToolBase):
|
|
|
299
317
|
payload: dict[str, Any],
|
|
300
318
|
fields: dict[str, Any] | None = None,
|
|
301
319
|
) -> dict[str, Any]:
|
|
320
|
+
"""执行任务相关逻辑。"""
|
|
302
321
|
self._require_app_record_and_node(app_key, record_id, workflow_node_id)
|
|
303
322
|
normalized_action = (action or "").strip().lower()
|
|
304
323
|
if normalized_action not in {"approve", "reject", "rollback", "transfer", "urge", "save_only"}:
|
|
@@ -494,6 +513,7 @@ class TaskContextTools(ToolBase):
|
|
|
494
513
|
payload: dict[str, Any],
|
|
495
514
|
prepared_fields: dict[str, Any] | None,
|
|
496
515
|
) -> dict[str, Any]:
|
|
516
|
+
"""执行内部辅助逻辑。"""
|
|
497
517
|
merged_answers = None
|
|
498
518
|
normalized_answers = None
|
|
499
519
|
if isinstance(prepared_fields, dict):
|
|
@@ -589,6 +609,7 @@ class TaskContextTools(ToolBase):
|
|
|
589
609
|
before_apply_status: Any,
|
|
590
610
|
runtime_baseline: dict[str, Any] | None = None,
|
|
591
611
|
) -> tuple[dict[str, Any], list[dict[str, Any]]]:
|
|
612
|
+
"""执行内部辅助逻辑。"""
|
|
592
613
|
verification: dict[str, Any] = {
|
|
593
614
|
"action_executed": True,
|
|
594
615
|
"runtime_continuation_verified": action == "urge",
|
|
@@ -730,6 +751,7 @@ class TaskContextTools(ToolBase):
|
|
|
730
751
|
expected_answers: list[dict[str, Any]],
|
|
731
752
|
task_context: dict[str, Any],
|
|
732
753
|
) -> tuple[dict[str, Any], list[dict[str, Any]]]:
|
|
754
|
+
"""执行内部辅助逻辑。"""
|
|
733
755
|
verification: dict[str, Any] = {
|
|
734
756
|
"action_executed": True,
|
|
735
757
|
"scope": "task_field_save",
|
|
@@ -843,6 +865,7 @@ class TaskContextTools(ToolBase):
|
|
|
843
865
|
record_id: int,
|
|
844
866
|
workflow_node_id: int,
|
|
845
867
|
) -> dict[str, Any]:
|
|
868
|
+
"""执行内部辅助逻辑。"""
|
|
846
869
|
baseline: dict[str, Any] = {
|
|
847
870
|
"workflow_log_visible": False,
|
|
848
871
|
"workflow_log_count": None,
|
|
@@ -894,6 +917,7 @@ class TaskContextTools(ToolBase):
|
|
|
894
917
|
source_error: QingflowApiError,
|
|
895
918
|
before_apply_status: Any,
|
|
896
919
|
) -> dict[str, Any]:
|
|
920
|
+
"""执行内部辅助逻辑。"""
|
|
897
921
|
verification, warnings = self._verify_task_action_runtime(
|
|
898
922
|
profile=profile,
|
|
899
923
|
context=context,
|
|
@@ -969,6 +993,7 @@ class TaskContextTools(ToolBase):
|
|
|
969
993
|
}
|
|
970
994
|
|
|
971
995
|
def _safe_task_list_items(self, *, profile: str, task_box: str, app_key: str) -> list[dict[str, Any]]:
|
|
996
|
+
"""执行内部辅助逻辑。"""
|
|
972
997
|
try:
|
|
973
998
|
response = self.task_list(
|
|
974
999
|
profile=profile,
|
|
@@ -1063,6 +1088,7 @@ class TaskContextTools(ToolBase):
|
|
|
1063
1088
|
return True
|
|
1064
1089
|
return False
|
|
1065
1090
|
|
|
1091
|
+
@tool_cn_name("任务关联报表详情")
|
|
1066
1092
|
def task_associated_report_detail_get(
|
|
1067
1093
|
self,
|
|
1068
1094
|
*,
|
|
@@ -1074,6 +1100,7 @@ class TaskContextTools(ToolBase):
|
|
|
1074
1100
|
page: int,
|
|
1075
1101
|
page_size: int,
|
|
1076
1102
|
) -> dict[str, Any]:
|
|
1103
|
+
"""执行任务相关逻辑。"""
|
|
1077
1104
|
self._require_app_record_and_node(app_key, record_id, workflow_node_id)
|
|
1078
1105
|
if report_id <= 0:
|
|
1079
1106
|
raise_tool_error(QingflowApiError.config_error("report_id must be positive"))
|
|
@@ -1253,6 +1280,7 @@ class TaskContextTools(ToolBase):
|
|
|
1253
1280
|
|
|
1254
1281
|
return self._run(profile, runner)
|
|
1255
1282
|
|
|
1283
|
+
@tool_cn_name("任务流程日志")
|
|
1256
1284
|
def task_workflow_log_get(
|
|
1257
1285
|
self,
|
|
1258
1286
|
*,
|
|
@@ -1261,6 +1289,7 @@ class TaskContextTools(ToolBase):
|
|
|
1261
1289
|
record_id: int,
|
|
1262
1290
|
workflow_node_id: int,
|
|
1263
1291
|
) -> dict[str, Any]:
|
|
1292
|
+
"""执行任务相关逻辑。"""
|
|
1264
1293
|
self._require_app_record_and_node(app_key, record_id, workflow_node_id)
|
|
1265
1294
|
|
|
1266
1295
|
def runner(session_profile, context):
|
|
@@ -1330,6 +1359,7 @@ class TaskContextTools(ToolBase):
|
|
|
1330
1359
|
include_associated_reports: bool,
|
|
1331
1360
|
current_uid: int | None = None,
|
|
1332
1361
|
) -> dict[str, Any]:
|
|
1362
|
+
"""执行内部辅助逻辑。"""
|
|
1333
1363
|
audit_infos = self.backend.request(
|
|
1334
1364
|
"GET",
|
|
1335
1365
|
context,
|
|
@@ -1544,6 +1574,12 @@ class TaskContextTools(ToolBase):
|
|
|
1544
1574
|
},
|
|
1545
1575
|
},
|
|
1546
1576
|
}
|
|
1577
|
+
action_metadata = self._compact_task_action_metadata(capabilities)
|
|
1578
|
+
if action_metadata:
|
|
1579
|
+
compact["action_metadata"] = action_metadata
|
|
1580
|
+
editable_metadata = self._compact_task_editable_metadata(update_schema)
|
|
1581
|
+
if editable_metadata:
|
|
1582
|
+
compact["editable_metadata"] = editable_metadata
|
|
1547
1583
|
return compact
|
|
1548
1584
|
|
|
1549
1585
|
def _compact_task_action_metadata(self, capabilities: dict[str, Any]) -> dict[str, Any]:
|
|
@@ -1681,6 +1717,7 @@ class TaskContextTools(ToolBase):
|
|
|
1681
1717
|
}
|
|
1682
1718
|
|
|
1683
1719
|
def _normalize_task_item(self, raw: dict[str, Any], *, task_box: str, flow_status: str) -> dict[str, Any]:
|
|
1720
|
+
"""执行内部辅助逻辑。"""
|
|
1684
1721
|
app_key = raw.get("appKey") or raw.get("app_key")
|
|
1685
1722
|
record_id = raw.get("rowRecordId") or raw.get("recordId") or raw.get("applyId")
|
|
1686
1723
|
workflow_node_id = raw.get("nodeId") or raw.get("auditNodeId")
|
|
@@ -1698,6 +1735,7 @@ class TaskContextTools(ToolBase):
|
|
|
1698
1735
|
}
|
|
1699
1736
|
|
|
1700
1737
|
def _select_task_node(self, infos: Any, workflow_node_id: int, *, app_key: str, record_id: int) -> dict[str, Any]:
|
|
1738
|
+
"""执行内部辅助逻辑。"""
|
|
1701
1739
|
if not isinstance(infos, list) or not infos:
|
|
1702
1740
|
raise_tool_error(
|
|
1703
1741
|
QingflowApiError.config_error(
|
|
@@ -1726,6 +1764,7 @@ class TaskContextTools(ToolBase):
|
|
|
1726
1764
|
warnings: list[JSONObject] | None = None,
|
|
1727
1765
|
save_only_source: str = "workflow_editable_que_ids",
|
|
1728
1766
|
) -> dict[str, Any]:
|
|
1767
|
+
"""执行内部辅助逻辑。"""
|
|
1729
1768
|
available_actions = ["approve"]
|
|
1730
1769
|
if self._coerce_bool(node_info.get("rejectBtnStatus")):
|
|
1731
1770
|
available_actions.append("reject")
|
|
@@ -1776,6 +1815,7 @@ class TaskContextTools(ToolBase):
|
|
|
1776
1815
|
node_info: dict[str, Any],
|
|
1777
1816
|
current_answers: Any,
|
|
1778
1817
|
) -> dict[str, Any]:
|
|
1818
|
+
"""执行内部辅助逻辑。"""
|
|
1779
1819
|
try:
|
|
1780
1820
|
app_schema = self._record_tools._get_form_schema(profile, context, app_key, force_refresh=False)
|
|
1781
1821
|
except QingflowApiError as error:
|
|
@@ -1896,6 +1936,7 @@ class TaskContextTools(ToolBase):
|
|
|
1896
1936
|
current_answers: Any,
|
|
1897
1937
|
editable_question_ids: set[int],
|
|
1898
1938
|
) -> tuple[FieldIndex, list[JSONObject]]:
|
|
1939
|
+
"""执行内部辅助逻辑。"""
|
|
1899
1940
|
if not editable_question_ids:
|
|
1900
1941
|
return index, []
|
|
1901
1942
|
missing_field_ids = {
|
|
@@ -1935,6 +1976,7 @@ class TaskContextTools(ToolBase):
|
|
|
1935
1976
|
workflow_node_id: int,
|
|
1936
1977
|
node_info: dict[str, Any],
|
|
1937
1978
|
) -> tuple[set[int], list[JSONObject], str]:
|
|
1979
|
+
"""执行内部辅助逻辑。"""
|
|
1938
1980
|
warnings: list[JSONObject] = []
|
|
1939
1981
|
try:
|
|
1940
1982
|
payload = self.backend.request(
|
|
@@ -1964,6 +2006,7 @@ class TaskContextTools(ToolBase):
|
|
|
1964
2006
|
app_key: str,
|
|
1965
2007
|
workflow_node_id: int,
|
|
1966
2008
|
) -> tuple[bool, list[JSONObject], str]:
|
|
2009
|
+
"""执行内部辅助逻辑。"""
|
|
1967
2010
|
try:
|
|
1968
2011
|
payload = self.backend.request(
|
|
1969
2012
|
"GET",
|
|
@@ -1983,6 +2026,7 @@ class TaskContextTools(ToolBase):
|
|
|
1983
2026
|
return bool(self._extract_question_ids(payload)), [], "workflow_editable_que_ids"
|
|
1984
2027
|
|
|
1985
2028
|
def _extract_question_ids(self, payload: Any) -> set[int]:
|
|
2029
|
+
"""执行内部辅助逻辑。"""
|
|
1986
2030
|
candidates: list[Any] = []
|
|
1987
2031
|
if isinstance(payload, list):
|
|
1988
2032
|
candidates = payload
|
|
@@ -2006,6 +2050,7 @@ class TaskContextTools(ToolBase):
|
|
|
2006
2050
|
return question_ids
|
|
2007
2051
|
|
|
2008
2052
|
def _editable_ids_from_que_auth_setting(self, payload: Any) -> set[int]:
|
|
2053
|
+
"""执行内部辅助逻辑。"""
|
|
2009
2054
|
if not isinstance(payload, list):
|
|
2010
2055
|
return set()
|
|
2011
2056
|
editable_ids: set[int] = set()
|
|
@@ -2040,6 +2085,7 @@ class TaskContextTools(ToolBase):
|
|
|
2040
2085
|
task_context: dict[str, Any],
|
|
2041
2086
|
fields: dict[str, Any],
|
|
2042
2087
|
) -> dict[str, Any]:
|
|
2088
|
+
"""执行内部辅助逻辑。"""
|
|
2043
2089
|
record = task_context.get("record") if isinstance(task_context.get("record"), dict) else {}
|
|
2044
2090
|
current_answers = record.get("answers") if isinstance(record.get("answers"), list) else []
|
|
2045
2091
|
node = task_context.get("node") if isinstance(task_context.get("node"), dict) else {}
|
|
@@ -2124,6 +2170,7 @@ class TaskContextTools(ToolBase):
|
|
|
2124
2170
|
index: Any,
|
|
2125
2171
|
effective_editable_ids: set[int],
|
|
2126
2172
|
) -> list[dict[str, Any]]:
|
|
2173
|
+
"""执行内部辅助逻辑。"""
|
|
2127
2174
|
if index is None:
|
|
2128
2175
|
return []
|
|
2129
2176
|
field_errors: list[dict[str, Any]] = []
|
|
@@ -2173,6 +2220,7 @@ class TaskContextTools(ToolBase):
|
|
|
2173
2220
|
workflow_node_id: int,
|
|
2174
2221
|
apply_answers: list[dict[str, Any]],
|
|
2175
2222
|
) -> dict[str, Any]:
|
|
2223
|
+
"""执行内部辅助逻辑。"""
|
|
2176
2224
|
def runner(session_profile, context):
|
|
2177
2225
|
result = self.backend.request(
|
|
2178
2226
|
"POST",
|
|
@@ -2192,6 +2240,7 @@ class TaskContextTools(ToolBase):
|
|
|
2192
2240
|
return self._run(profile, runner)
|
|
2193
2241
|
|
|
2194
2242
|
def _build_visibility(self, node_info: dict[str, Any], detail: dict[str, Any]) -> dict[str, bool]:
|
|
2243
|
+
"""执行内部辅助逻辑。"""
|
|
2195
2244
|
return {
|
|
2196
2245
|
"comment_visible": self._coerce_bool(node_info.get("commentStatus")),
|
|
2197
2246
|
"audit_record_visible": self._coerce_bool(node_info.get("auditRecordVisible")),
|
|
@@ -2201,12 +2250,14 @@ class TaskContextTools(ToolBase):
|
|
|
2201
2250
|
}
|
|
2202
2251
|
|
|
2203
2252
|
def _resolve_associated_report_visible(self, node_info: dict[str, Any], detail: dict[str, Any]) -> bool:
|
|
2253
|
+
"""执行内部辅助逻辑。"""
|
|
2204
2254
|
node_visible = node_info.get("asosChartVisible")
|
|
2205
2255
|
if node_visible is not None:
|
|
2206
2256
|
return self._coerce_bool(node_visible)
|
|
2207
2257
|
return self._coerce_bool(detail.get("viewAsosChartVisible"))
|
|
2208
2258
|
|
|
2209
2259
|
def _normalize_associated_report(self, raw: dict[str, Any]) -> dict[str, Any]:
|
|
2260
|
+
"""执行内部辅助逻辑。"""
|
|
2210
2261
|
graph_type = str(raw.get("graphType") or "").strip().lower()
|
|
2211
2262
|
source_type = str(raw.get("sourceType") or "").strip().lower()
|
|
2212
2263
|
return {
|
|
@@ -2222,6 +2273,7 @@ class TaskContextTools(ToolBase):
|
|
|
2222
2273
|
}
|
|
2223
2274
|
|
|
2224
2275
|
def _rollback_candidate_items(self, payload: Any) -> list[dict[str, Any]]:
|
|
2276
|
+
"""执行内部辅助逻辑。"""
|
|
2225
2277
|
if isinstance(payload, dict):
|
|
2226
2278
|
revert_nodes = payload.get("revertNodes")
|
|
2227
2279
|
if isinstance(revert_nodes, list):
|
|
@@ -2229,6 +2281,7 @@ class TaskContextTools(ToolBase):
|
|
|
2229
2281
|
return [item for item in _approval_page_items(payload) if isinstance(item, dict)]
|
|
2230
2282
|
|
|
2231
2283
|
def _filter_transfer_members(self, items: Any, *, current_uid: int | None) -> list[dict[str, Any]]:
|
|
2284
|
+
"""执行内部辅助逻辑。"""
|
|
2232
2285
|
if not isinstance(items, list):
|
|
2233
2286
|
return []
|
|
2234
2287
|
filtered: list[dict[str, Any]] = []
|
|
@@ -2315,6 +2368,7 @@ class TaskContextTools(ToolBase):
|
|
|
2315
2368
|
return json.dumps(item, ensure_ascii=False, sort_keys=True, default=str)
|
|
2316
2369
|
|
|
2317
2370
|
def _find_associated_report(self, task_context: dict[str, Any], report_id: int) -> dict[str, Any] | None:
|
|
2371
|
+
"""执行内部辅助逻辑。"""
|
|
2318
2372
|
associated_reports = ((task_context.get("associated_reports") or {}).get("items") or [])
|
|
2319
2373
|
for item in associated_reports:
|
|
2320
2374
|
if isinstance(item, dict) and item.get("report_id") == report_id:
|
|
@@ -2322,6 +2376,7 @@ class TaskContextTools(ToolBase):
|
|
|
2322
2376
|
return None
|
|
2323
2377
|
|
|
2324
2378
|
def _build_association_query(self, asos_chart: dict[str, Any], answers: list[dict[str, Any]]) -> dict[str, Any]:
|
|
2379
|
+
"""执行内部辅助逻辑。"""
|
|
2325
2380
|
key_que_ids = self._collect_match_rule_question_ids(asos_chart.get("matchRules") or [])
|
|
2326
2381
|
key_values: list[dict[str, Any]] = []
|
|
2327
2382
|
for answer in answers:
|
|
@@ -2356,6 +2411,7 @@ class TaskContextTools(ToolBase):
|
|
|
2356
2411
|
}
|
|
2357
2412
|
|
|
2358
2413
|
def _collect_match_rule_question_ids(self, match_rules: Any) -> set[int]:
|
|
2414
|
+
"""执行内部辅助逻辑。"""
|
|
2359
2415
|
question_ids: set[int] = set()
|
|
2360
2416
|
|
|
2361
2417
|
def visit(node: Any) -> None:
|
|
@@ -2377,6 +2433,7 @@ class TaskContextTools(ToolBase):
|
|
|
2377
2433
|
return question_ids
|
|
2378
2434
|
|
|
2379
2435
|
def _extract_answer_values(self, answer: dict[str, Any]) -> list[str]:
|
|
2436
|
+
"""执行内部辅助逻辑。"""
|
|
2380
2437
|
values = answer.get("values")
|
|
2381
2438
|
if not isinstance(values, list):
|
|
2382
2439
|
return []
|
|
@@ -2404,6 +2461,7 @@ class TaskContextTools(ToolBase):
|
|
|
2404
2461
|
return deduped
|
|
2405
2462
|
|
|
2406
2463
|
def _sanitize_associated_chart(self, asos_chart: dict[str, Any]) -> dict[str, Any]:
|
|
2464
|
+
"""执行内部辅助逻辑。"""
|
|
2407
2465
|
return {
|
|
2408
2466
|
"id": asos_chart.get("id"),
|
|
2409
2467
|
"appKey": asos_chart.get("appKey"),
|
|
@@ -2418,6 +2476,7 @@ class TaskContextTools(ToolBase):
|
|
|
2418
2476
|
}
|
|
2419
2477
|
|
|
2420
2478
|
def _qingflow_chart_uses_apply_filter(self, context: BackendRequestContext, chart_key: str) -> bool:
|
|
2479
|
+
"""执行内部辅助逻辑。"""
|
|
2421
2480
|
if not chart_key:
|
|
2422
2481
|
return False
|
|
2423
2482
|
try:
|
|
@@ -2433,6 +2492,7 @@ class TaskContextTools(ToolBase):
|
|
|
2433
2492
|
return self._coerce_bool(auth.get("detailedViewStatus")) and auth.get("lastViewType") == 1
|
|
2434
2493
|
|
|
2435
2494
|
def _normalize_chart_result(self, payload: Any) -> dict[str, Any]:
|
|
2495
|
+
"""执行内部辅助逻辑。"""
|
|
2436
2496
|
if isinstance(payload, dict):
|
|
2437
2497
|
rows = payload.get("rows")
|
|
2438
2498
|
if not isinstance(rows, list):
|
|
@@ -2455,6 +2515,7 @@ class TaskContextTools(ToolBase):
|
|
|
2455
2515
|
return {"summary": {}, "rows": [], "series": [], "metrics": []}
|
|
2456
2516
|
|
|
2457
2517
|
def _normalize_workflow_logs(self, payload: Any) -> list[dict[str, Any]]:
|
|
2518
|
+
"""执行内部辅助逻辑。"""
|
|
2458
2519
|
if isinstance(payload, dict):
|
|
2459
2520
|
page = payload.get("list") if isinstance(payload.get("list"), list) else payload.get("rows")
|
|
2460
2521
|
if not isinstance(page, list):
|
|
@@ -2503,6 +2564,7 @@ class TaskContextTools(ToolBase):
|
|
|
2503
2564
|
return items
|
|
2504
2565
|
|
|
2505
2566
|
def _workflow_log_digest(self, items: list[dict[str, Any]]) -> str | None:
|
|
2567
|
+
"""执行内部辅助逻辑。"""
|
|
2506
2568
|
if not items:
|
|
2507
2569
|
return None
|
|
2508
2570
|
try:
|
|
@@ -2511,6 +2573,7 @@ class TaskContextTools(ToolBase):
|
|
|
2511
2573
|
return str(items)
|
|
2512
2574
|
|
|
2513
2575
|
def _first_nested_operation_detail(self, operation: dict[str, Any]) -> Any:
|
|
2576
|
+
"""执行内部辅助逻辑。"""
|
|
2514
2577
|
for key in ("approval", "filling", "cc", "applicant", "qRobotAdd", "qRobotUpdate", "webhook", "qRobotSMS", "qRobotMail"):
|
|
2515
2578
|
value = operation.get(key)
|
|
2516
2579
|
if value is not None:
|
|
@@ -2518,6 +2581,7 @@ class TaskContextTools(ToolBase):
|
|
|
2518
2581
|
return None
|
|
2519
2582
|
|
|
2520
2583
|
def _extract_remark(self, detail: Any) -> Any:
|
|
2584
|
+
"""执行内部辅助逻辑。"""
|
|
2521
2585
|
if not isinstance(detail, dict):
|
|
2522
2586
|
return None
|
|
2523
2587
|
for key in ("remark", "feedback", "comment", "content"):
|
|
@@ -2527,6 +2591,7 @@ class TaskContextTools(ToolBase):
|
|
|
2527
2591
|
return None
|
|
2528
2592
|
|
|
2529
2593
|
def _extract_signature_url(self, detail: Any) -> Any:
|
|
2594
|
+
"""执行内部辅助逻辑。"""
|
|
2530
2595
|
if not isinstance(detail, dict):
|
|
2531
2596
|
return None
|
|
2532
2597
|
for key in ("signatureUrl", "handSignImageUrl"):
|
|
@@ -2536,6 +2601,7 @@ class TaskContextTools(ToolBase):
|
|
|
2536
2601
|
return None
|
|
2537
2602
|
|
|
2538
2603
|
def _extract_attachments(self, detail: Any) -> Any:
|
|
2604
|
+
"""执行内部辅助逻辑。"""
|
|
2539
2605
|
if not isinstance(detail, dict):
|
|
2540
2606
|
return []
|
|
2541
2607
|
for key in ("attachments", "files", "uploadFiles"):
|
|
@@ -2545,6 +2611,7 @@ class TaskContextTools(ToolBase):
|
|
|
2545
2611
|
return []
|
|
2546
2612
|
|
|
2547
2613
|
def _extract_audit_feedback(self, payload: dict[str, Any]) -> str | None:
|
|
2614
|
+
"""执行内部辅助逻辑。"""
|
|
2548
2615
|
for key in ("audit_feedback", "auditFeedback"):
|
|
2549
2616
|
value = payload.get(key)
|
|
2550
2617
|
if isinstance(value, str) and value.strip():
|
|
@@ -2552,6 +2619,7 @@ class TaskContextTools(ToolBase):
|
|
|
2552
2619
|
return None
|
|
2553
2620
|
|
|
2554
2621
|
def _extract_positive_int(self, payload: dict[str, Any], key: str, *, aliases: tuple[str, ...] = ()) -> int:
|
|
2622
|
+
"""执行内部辅助逻辑。"""
|
|
2555
2623
|
candidates = (key, *aliases)
|
|
2556
2624
|
value: Any = None
|
|
2557
2625
|
for candidate in candidates:
|
|
@@ -2564,6 +2632,7 @@ class TaskContextTools(ToolBase):
|
|
|
2564
2632
|
return value
|
|
2565
2633
|
|
|
2566
2634
|
def _require_app_record_and_node(self, app_key: str, record_id: int, workflow_node_id: int) -> None:
|
|
2635
|
+
"""执行内部辅助逻辑。"""
|
|
2567
2636
|
if not app_key:
|
|
2568
2637
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
2569
2638
|
if record_id <= 0:
|
|
@@ -2572,6 +2641,7 @@ class TaskContextTools(ToolBase):
|
|
|
2572
2641
|
raise_tool_error(QingflowApiError.config_error("workflow_node_id must be positive"))
|
|
2573
2642
|
|
|
2574
2643
|
def _coerce_bool(self, value: Any) -> bool:
|
|
2644
|
+
"""执行内部辅助逻辑。"""
|
|
2575
2645
|
if isinstance(value, bool):
|
|
2576
2646
|
return value
|
|
2577
2647
|
if isinstance(value, int):
|
|
@@ -2581,6 +2651,7 @@ class TaskContextTools(ToolBase):
|
|
|
2581
2651
|
return bool(value)
|
|
2582
2652
|
|
|
2583
2653
|
def _request_route_payload(self, context: BackendRequestContext) -> dict[str, Any]:
|
|
2654
|
+
"""执行内部辅助逻辑。"""
|
|
2584
2655
|
describe_route = getattr(self.backend, "describe_route", None)
|
|
2585
2656
|
if callable(describe_route):
|
|
2586
2657
|
payload = describe_route(context)
|