@josephyan/qingflow-cli 0.2.0-beta.984 → 0.2.0-beta.986
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 +47 -21
- package/src/qingflow_mcp/cli/commands/auth.py +14 -43
- package/src/qingflow_mcp/cli/commands/task.py +4 -1
- package/src/qingflow_mcp/cli/commands/workspace.py +0 -8
- package/src/qingflow_mcp/cli/formatters.py +0 -21
- package/src/qingflow_mcp/config.py +39 -0
- package/src/qingflow_mcp/errors.py +2 -2
- package/src/qingflow_mcp/public_surface.py +2 -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/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 +258 -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 +205 -6
- 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 +14 -225
|
@@ -8,15 +8,26 @@ from ..config import DEFAULT_PROFILE
|
|
|
8
8
|
from ..errors import QingflowApiError, raise_tool_error
|
|
9
9
|
from ..json_types import JSONObject
|
|
10
10
|
from ..list_type_labels import get_record_list_type_label
|
|
11
|
-
from .base import ToolBase
|
|
11
|
+
from .base import ToolBase, tool_cn_name
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class ApprovalTools(ToolBase):
|
|
15
|
+
"""审批工具(中文名:审批数据与候选范围)。
|
|
16
|
+
|
|
17
|
+
类型:审批辅助工具。
|
|
18
|
+
主要职责:
|
|
19
|
+
1. 查询审批相关列表与详情;
|
|
20
|
+
2. 提供审批节点候选范围与运行时上下文辅助;
|
|
21
|
+
3. 为任务执行类工具提供审批侧数据支撑。
|
|
22
|
+
"""
|
|
23
|
+
|
|
15
24
|
def __init__(self, sessions, backend) -> None: # type: ignore[no-untyped-def]
|
|
25
|
+
"""执行内部辅助逻辑。"""
|
|
16
26
|
super().__init__(sessions, backend)
|
|
17
27
|
self._form_id_cache: dict[str, int] = {}
|
|
18
28
|
|
|
19
29
|
def register(self, mcp: FastMCP) -> None:
|
|
30
|
+
"""注册当前工具到 MCP 服务。"""
|
|
20
31
|
@mcp.tool()
|
|
21
32
|
def record_comment_write(
|
|
22
33
|
profile: str = DEFAULT_PROFILE,
|
|
@@ -137,7 +148,9 @@ class ApprovalTools(ToolBase):
|
|
|
137
148
|
keyword=keyword,
|
|
138
149
|
)
|
|
139
150
|
|
|
151
|
+
@tool_cn_name("写评论")
|
|
140
152
|
def record_comment_write(self, *, profile: str, app_key: str, record_id: int, payload: dict[str, Any]) -> dict[str, Any]:
|
|
153
|
+
"""执行记录相关逻辑。"""
|
|
141
154
|
raw = self.record_comment_add(profile=profile, app_key=app_key, apply_id=record_id, payload=payload)
|
|
142
155
|
return self._public_action_response(
|
|
143
156
|
raw,
|
|
@@ -146,6 +159,7 @@ class ApprovalTools(ToolBase):
|
|
|
146
159
|
selection={},
|
|
147
160
|
)
|
|
148
161
|
|
|
162
|
+
@tool_cn_name("评论提及")
|
|
149
163
|
def record_comment_mentions(
|
|
150
164
|
self,
|
|
151
165
|
*,
|
|
@@ -157,6 +171,7 @@ class ApprovalTools(ToolBase):
|
|
|
157
171
|
list_type: int | None = None,
|
|
158
172
|
keyword: str | None = None,
|
|
159
173
|
) -> dict[str, Any]:
|
|
174
|
+
"""执行记录相关逻辑。"""
|
|
160
175
|
raw = self.record_comment_mention_candidates(
|
|
161
176
|
profile=profile,
|
|
162
177
|
app_key=app_key,
|
|
@@ -180,7 +195,9 @@ class ApprovalTools(ToolBase):
|
|
|
180
195
|
selection={"app_key": app_key, "record_id": record_id, "list_type": list_type, "keyword": keyword},
|
|
181
196
|
)
|
|
182
197
|
|
|
198
|
+
@tool_cn_name("任务通过")
|
|
183
199
|
def task_approve(self, *, profile: str, app_key: str, record_id: int, payload: dict[str, Any], fields: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
200
|
+
"""执行任务相关逻辑。"""
|
|
184
201
|
if fields:
|
|
185
202
|
return self._delegate_task_action(
|
|
186
203
|
profile=profile,
|
|
@@ -200,7 +217,9 @@ class ApprovalTools(ToolBase):
|
|
|
200
217
|
human_review=True,
|
|
201
218
|
)
|
|
202
219
|
|
|
220
|
+
@tool_cn_name("任务拒绝")
|
|
203
221
|
def task_reject(self, *, profile: str, app_key: str, record_id: int, payload: dict[str, Any], fields: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
222
|
+
"""执行任务相关逻辑。"""
|
|
204
223
|
if fields:
|
|
205
224
|
return self._delegate_task_action(
|
|
206
225
|
profile=profile,
|
|
@@ -220,7 +239,9 @@ class ApprovalTools(ToolBase):
|
|
|
220
239
|
human_review=True,
|
|
221
240
|
)
|
|
222
241
|
|
|
242
|
+
@tool_cn_name("任务退回候选")
|
|
223
243
|
def task_rollback_candidates(self, *, profile: str, app_key: str, record_id: int, workflow_node_id: int) -> dict[str, Any]:
|
|
244
|
+
"""执行任务相关逻辑。"""
|
|
224
245
|
raw = self.record_rollback_candidates(profile=profile, app_key=app_key, apply_id=record_id, audit_node_id=workflow_node_id)
|
|
225
246
|
items = _approval_page_items(raw.get("result"))
|
|
226
247
|
return self._public_page_response(
|
|
@@ -230,7 +251,9 @@ class ApprovalTools(ToolBase):
|
|
|
230
251
|
selection={"app_key": app_key, "record_id": record_id, "workflow_node_id": workflow_node_id},
|
|
231
252
|
)
|
|
232
253
|
|
|
254
|
+
@tool_cn_name("任务退回")
|
|
233
255
|
def task_rollback(self, *, profile: str, app_key: str, record_id: int, payload: dict[str, Any], fields: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
256
|
+
"""执行任务相关逻辑。"""
|
|
234
257
|
if fields:
|
|
235
258
|
return self._delegate_task_action(
|
|
236
259
|
profile=profile,
|
|
@@ -250,7 +273,9 @@ class ApprovalTools(ToolBase):
|
|
|
250
273
|
human_review=True,
|
|
251
274
|
)
|
|
252
275
|
|
|
276
|
+
@tool_cn_name("任务转交")
|
|
253
277
|
def task_transfer(self, *, profile: str, app_key: str, record_id: int, payload: dict[str, Any], fields: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
278
|
+
"""执行任务相关逻辑。"""
|
|
254
279
|
if fields:
|
|
255
280
|
return self._delegate_task_action(
|
|
256
281
|
profile=profile,
|
|
@@ -271,6 +296,7 @@ class ApprovalTools(ToolBase):
|
|
|
271
296
|
human_review=True,
|
|
272
297
|
)
|
|
273
298
|
|
|
299
|
+
@tool_cn_name("任务仅保存")
|
|
274
300
|
def task_save_only(
|
|
275
301
|
self,
|
|
276
302
|
*,
|
|
@@ -280,6 +306,7 @@ class ApprovalTools(ToolBase):
|
|
|
280
306
|
workflow_node_id: int,
|
|
281
307
|
fields: dict[str, Any],
|
|
282
308
|
) -> dict[str, Any]:
|
|
309
|
+
"""执行任务相关逻辑。"""
|
|
283
310
|
return self._delegate_task_action(
|
|
284
311
|
profile=profile,
|
|
285
312
|
app_key=app_key,
|
|
@@ -291,6 +318,7 @@ class ApprovalTools(ToolBase):
|
|
|
291
318
|
workflow_node_id=workflow_node_id,
|
|
292
319
|
)
|
|
293
320
|
|
|
321
|
+
@tool_cn_name("任务转交候选")
|
|
294
322
|
def task_transfer_candidates(
|
|
295
323
|
self,
|
|
296
324
|
*,
|
|
@@ -302,6 +330,7 @@ class ApprovalTools(ToolBase):
|
|
|
302
330
|
workflow_node_id: int = 0,
|
|
303
331
|
keyword: str | None = None,
|
|
304
332
|
) -> dict[str, Any]:
|
|
333
|
+
"""执行任务相关逻辑。"""
|
|
305
334
|
raw = self.record_transfer_candidates(
|
|
306
335
|
profile=profile,
|
|
307
336
|
app_key=app_key,
|
|
@@ -327,7 +356,9 @@ class ApprovalTools(ToolBase):
|
|
|
327
356
|
selection={"app_key": app_key, "record_id": record_id, "workflow_node_id": workflow_node_id, "keyword": keyword},
|
|
328
357
|
)
|
|
329
358
|
|
|
359
|
+
@tool_cn_name("新增评论")
|
|
330
360
|
def record_comment_add(self, *, profile: str, app_key: str, apply_id: int, payload: dict[str, Any]) -> dict[str, Any]:
|
|
361
|
+
"""执行记录相关逻辑。"""
|
|
331
362
|
self._require_app_and_apply(app_key, apply_id)
|
|
332
363
|
self._validate_comment_payload(payload)
|
|
333
364
|
|
|
@@ -344,7 +375,9 @@ class ApprovalTools(ToolBase):
|
|
|
344
375
|
|
|
345
376
|
return self._run(profile, runner)
|
|
346
377
|
|
|
378
|
+
@tool_cn_name("评论列表")
|
|
347
379
|
def record_comment_list(self, *, profile: str, app_key: str, apply_id: int, page_size: int = 20, list_type: int | None = None, page_num: int | None = 1) -> dict[str, Any]:
|
|
380
|
+
"""执行记录相关逻辑。"""
|
|
348
381
|
self._require_app_and_apply(app_key, apply_id)
|
|
349
382
|
|
|
350
383
|
def runner(session_profile, context):
|
|
@@ -380,6 +413,7 @@ class ApprovalTools(ToolBase):
|
|
|
380
413
|
selection={"app_key": app_key, "record_id": apply_id, "list_type": list_type},
|
|
381
414
|
)
|
|
382
415
|
|
|
416
|
+
@tool_cn_name("评论提及候选")
|
|
383
417
|
def record_comment_mention_candidates(
|
|
384
418
|
self,
|
|
385
419
|
*,
|
|
@@ -391,6 +425,7 @@ class ApprovalTools(ToolBase):
|
|
|
391
425
|
list_type: int | None = None,
|
|
392
426
|
keyword: str | None = None,
|
|
393
427
|
) -> dict[str, Any]:
|
|
428
|
+
"""执行记录相关逻辑。"""
|
|
394
429
|
self._require_app_and_apply(app_key, apply_id)
|
|
395
430
|
|
|
396
431
|
def runner(session_profile, context):
|
|
@@ -413,7 +448,9 @@ class ApprovalTools(ToolBase):
|
|
|
413
448
|
|
|
414
449
|
return self._run(profile, runner)
|
|
415
450
|
|
|
451
|
+
@tool_cn_name("评论标记已读")
|
|
416
452
|
def record_comment_mark_read(self, *, profile: str, app_key: str, apply_id: int) -> dict[str, Any]:
|
|
453
|
+
"""执行记录相关逻辑。"""
|
|
417
454
|
self._require_app_and_apply(app_key, apply_id)
|
|
418
455
|
|
|
419
456
|
def runner(session_profile, context):
|
|
@@ -435,7 +472,9 @@ class ApprovalTools(ToolBase):
|
|
|
435
472
|
selection={},
|
|
436
473
|
)
|
|
437
474
|
|
|
475
|
+
@tool_cn_name("评论统计")
|
|
438
476
|
def record_comment_stats(self, *, profile: str, app_key: str, apply_id: int) -> dict[str, Any]:
|
|
477
|
+
"""执行记录相关逻辑。"""
|
|
439
478
|
self._require_app_and_apply(app_key, apply_id)
|
|
440
479
|
|
|
441
480
|
def runner(session_profile, context):
|
|
@@ -451,7 +490,9 @@ class ApprovalTools(ToolBase):
|
|
|
451
490
|
|
|
452
491
|
return self._run(profile, runner)
|
|
453
492
|
|
|
493
|
+
@tool_cn_name("记录通过")
|
|
454
494
|
def record_approve(self, *, profile: str, app_key: str, apply_id: int, payload: dict[str, Any]) -> dict[str, Any]:
|
|
495
|
+
"""执行记录相关逻辑。"""
|
|
455
496
|
self._require_app_and_apply(app_key, apply_id)
|
|
456
497
|
body = self._require_dict(payload)
|
|
457
498
|
|
|
@@ -471,7 +512,9 @@ class ApprovalTools(ToolBase):
|
|
|
471
512
|
|
|
472
513
|
return self._run(profile, runner)
|
|
473
514
|
|
|
515
|
+
@tool_cn_name("记录拒绝")
|
|
474
516
|
def record_reject(self, *, profile: str, app_key: str, apply_id: int, payload: dict[str, Any]) -> dict[str, Any]:
|
|
517
|
+
"""执行记录相关逻辑。"""
|
|
475
518
|
self._require_app_and_apply(app_key, apply_id)
|
|
476
519
|
body = self._require_dict(payload)
|
|
477
520
|
|
|
@@ -491,7 +534,9 @@ class ApprovalTools(ToolBase):
|
|
|
491
534
|
|
|
492
535
|
return self._run(profile, runner)
|
|
493
536
|
|
|
537
|
+
@tool_cn_name("记录退回候选")
|
|
494
538
|
def record_rollback_candidates(self, *, profile: str, app_key: str, apply_id: int, audit_node_id: int) -> dict[str, Any]:
|
|
539
|
+
"""执行记录相关逻辑。"""
|
|
495
540
|
self._require_app_and_apply(app_key, apply_id)
|
|
496
541
|
if audit_node_id <= 0:
|
|
497
542
|
raise_tool_error(QingflowApiError.config_error("audit_node_id must be positive"))
|
|
@@ -514,7 +559,9 @@ class ApprovalTools(ToolBase):
|
|
|
514
559
|
|
|
515
560
|
return self._run(profile, runner)
|
|
516
561
|
|
|
562
|
+
@tool_cn_name("记录退回")
|
|
517
563
|
def record_rollback(self, *, profile: str, app_key: str, apply_id: int, payload: dict[str, Any]) -> dict[str, Any]:
|
|
564
|
+
"""执行记录相关逻辑。"""
|
|
518
565
|
self._require_app_and_apply(app_key, apply_id)
|
|
519
566
|
body = self._require_dict(payload)
|
|
520
567
|
self._validate_audit_payload(body)
|
|
@@ -532,7 +579,9 @@ class ApprovalTools(ToolBase):
|
|
|
532
579
|
|
|
533
580
|
return self._run(profile, runner)
|
|
534
581
|
|
|
582
|
+
@tool_cn_name("记录转交")
|
|
535
583
|
def record_transfer(self, *, profile: str, app_key: str, apply_id: int, payload: dict[str, Any]) -> dict[str, Any]:
|
|
584
|
+
"""执行记录相关逻辑。"""
|
|
536
585
|
self._require_app_and_apply(app_key, apply_id)
|
|
537
586
|
body = self._require_dict(payload)
|
|
538
587
|
self._validate_audit_payload(body, require_uid=True)
|
|
@@ -550,6 +599,7 @@ class ApprovalTools(ToolBase):
|
|
|
550
599
|
|
|
551
600
|
return self._run(profile, runner)
|
|
552
601
|
|
|
602
|
+
@tool_cn_name("记录转交候选")
|
|
553
603
|
def record_transfer_candidates(
|
|
554
604
|
self,
|
|
555
605
|
*,
|
|
@@ -561,6 +611,7 @@ class ApprovalTools(ToolBase):
|
|
|
561
611
|
audit_node_id: int = 0,
|
|
562
612
|
keyword: str | None = None,
|
|
563
613
|
) -> dict[str, Any]:
|
|
614
|
+
"""执行记录相关逻辑。"""
|
|
564
615
|
self._require_app_and_apply(app_key, apply_id)
|
|
565
616
|
if audit_node_id <= 0:
|
|
566
617
|
raise_tool_error(QingflowApiError.config_error("audit_node_id must be positive"))
|
|
@@ -581,7 +632,9 @@ class ApprovalTools(ToolBase):
|
|
|
581
632
|
|
|
582
633
|
return self._run(profile, runner)
|
|
583
634
|
|
|
635
|
+
@tool_cn_name("记录改派信息")
|
|
584
636
|
def record_reassign_get(self, *, profile: str, app_key: str, apply_id: int) -> dict[str, Any]:
|
|
637
|
+
"""执行记录相关逻辑。"""
|
|
585
638
|
self._require_app_and_apply(app_key, apply_id)
|
|
586
639
|
|
|
587
640
|
def runner(session_profile, context):
|
|
@@ -597,7 +650,9 @@ class ApprovalTools(ToolBase):
|
|
|
597
650
|
|
|
598
651
|
return self._run(profile, runner)
|
|
599
652
|
|
|
653
|
+
@tool_cn_name("记录改派")
|
|
600
654
|
def record_reassign(self, *, profile: str, app_key: str, apply_id: int, payload: dict[str, Any]) -> dict[str, Any]:
|
|
655
|
+
"""执行记录相关逻辑。"""
|
|
601
656
|
self._require_app_and_apply(app_key, apply_id)
|
|
602
657
|
body = self._require_dict(payload)
|
|
603
658
|
|
|
@@ -614,6 +669,7 @@ class ApprovalTools(ToolBase):
|
|
|
614
669
|
|
|
615
670
|
return self._run(profile, runner)
|
|
616
671
|
|
|
672
|
+
@tool_cn_name("会签候选")
|
|
617
673
|
def record_countersign_candidates(
|
|
618
674
|
self,
|
|
619
675
|
*,
|
|
@@ -625,6 +681,7 @@ class ApprovalTools(ToolBase):
|
|
|
625
681
|
audit_node_id: int = 0,
|
|
626
682
|
search_key: str | None = None,
|
|
627
683
|
) -> dict[str, Any]:
|
|
684
|
+
"""执行记录相关逻辑。"""
|
|
628
685
|
self._require_app_and_apply(app_key, apply_id)
|
|
629
686
|
if audit_node_id <= 0:
|
|
630
687
|
raise_tool_error(QingflowApiError.config_error("audit_node_id must be positive"))
|
|
@@ -645,7 +702,9 @@ class ApprovalTools(ToolBase):
|
|
|
645
702
|
|
|
646
703
|
return self._run(profile, runner)
|
|
647
704
|
|
|
705
|
+
@tool_cn_name("会签")
|
|
648
706
|
def record_countersign(self, *, profile: str, app_key: str, apply_id: int, payload: dict[str, Any]) -> dict[str, Any]:
|
|
707
|
+
"""执行记录相关逻辑。"""
|
|
649
708
|
self._require_app_and_apply(app_key, apply_id)
|
|
650
709
|
body = self._require_dict(payload)
|
|
651
710
|
self._validate_countersign_payload(body)
|
|
@@ -664,6 +723,7 @@ class ApprovalTools(ToolBase):
|
|
|
664
723
|
return self._run(profile, runner)
|
|
665
724
|
|
|
666
725
|
def _request_route_payload(self, context) -> JSONObject: # type: ignore[no-untyped-def]
|
|
726
|
+
"""执行内部辅助逻辑。"""
|
|
667
727
|
describe_route = getattr(self.backend, "describe_route", None)
|
|
668
728
|
if callable(describe_route):
|
|
669
729
|
payload = describe_route(context)
|
|
@@ -676,12 +736,14 @@ class ApprovalTools(ToolBase):
|
|
|
676
736
|
}
|
|
677
737
|
|
|
678
738
|
def _require_app_and_apply(self, app_key: str, apply_id: int) -> None:
|
|
739
|
+
"""执行内部辅助逻辑。"""
|
|
679
740
|
if not app_key:
|
|
680
741
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
681
742
|
if apply_id <= 0:
|
|
682
743
|
raise_tool_error(QingflowApiError.config_error("apply_id must be positive"))
|
|
683
744
|
|
|
684
745
|
def _validate_comment_payload(self, payload: dict[str, Any]) -> None:
|
|
746
|
+
"""执行内部辅助逻辑。"""
|
|
685
747
|
comment_detail = payload.get("commentDetail")
|
|
686
748
|
if not isinstance(comment_detail, dict):
|
|
687
749
|
raise_tool_error(QingflowApiError.config_error("payload.commentDetail must be an object"))
|
|
@@ -689,6 +751,7 @@ class ApprovalTools(ToolBase):
|
|
|
689
751
|
raise_tool_error(QingflowApiError.config_error("payload.commentDetail.commentMsg is required"))
|
|
690
752
|
|
|
691
753
|
def _normalize_approval_payload(self, profile: str, context, app_key: str, apply_id: int, payload: dict[str, Any]) -> JSONObject: # type: ignore[no-untyped-def]
|
|
754
|
+
"""执行内部辅助逻辑。"""
|
|
692
755
|
body: JSONObject = dict(payload)
|
|
693
756
|
self._normalize_alias(body, "auditFeedback", "audit_feedback")
|
|
694
757
|
self._normalize_alias(body, "uploadFileSize", "upload_file_size")
|
|
@@ -708,6 +771,7 @@ class ApprovalTools(ToolBase):
|
|
|
708
771
|
return body
|
|
709
772
|
|
|
710
773
|
def _extract_node_id(self, payload: JSONObject) -> int:
|
|
774
|
+
"""执行内部辅助逻辑。"""
|
|
711
775
|
node_id = payload.get("nodeId")
|
|
712
776
|
audit_node_id = payload.pop("auditNodeId", None)
|
|
713
777
|
if node_id is None:
|
|
@@ -719,6 +783,7 @@ class ApprovalTools(ToolBase):
|
|
|
719
783
|
return node_id
|
|
720
784
|
|
|
721
785
|
def _resolve_form_id(self, profile: str, context, app_key: str, *, explicit_form_id: Any | None) -> int: # type: ignore[no-untyped-def]
|
|
786
|
+
"""执行内部辅助逻辑。"""
|
|
722
787
|
if explicit_form_id is not None:
|
|
723
788
|
if not isinstance(explicit_form_id, int) or explicit_form_id <= 0:
|
|
724
789
|
raise_tool_error(QingflowApiError.config_error("payload.formId must be a positive integer"))
|
|
@@ -733,6 +798,7 @@ class ApprovalTools(ToolBase):
|
|
|
733
798
|
return self._get_form_id(profile, context, app_key)
|
|
734
799
|
|
|
735
800
|
def _get_form_id(self, profile: str, context, app_key: str) -> int: # type: ignore[no-untyped-def]
|
|
801
|
+
"""执行内部辅助逻辑。"""
|
|
736
802
|
cache_key = f"{profile}:{app_key}"
|
|
737
803
|
cached = self._form_id_cache.get(cache_key)
|
|
738
804
|
if cached is not None:
|
|
@@ -745,6 +811,7 @@ class ApprovalTools(ToolBase):
|
|
|
745
811
|
return form_id
|
|
746
812
|
|
|
747
813
|
def _match_or_fill_int(self, payload: JSONObject, *, field_name: str, expected_value: int) -> int:
|
|
814
|
+
"""执行内部辅助逻辑。"""
|
|
748
815
|
current = payload.get(field_name)
|
|
749
816
|
if current is None:
|
|
750
817
|
return expected_value
|
|
@@ -755,6 +822,7 @@ class ApprovalTools(ToolBase):
|
|
|
755
822
|
return current
|
|
756
823
|
|
|
757
824
|
def _normalize_alias(self, payload: JSONObject, canonical_key: str, alias_key: str) -> None:
|
|
825
|
+
"""执行内部辅助逻辑。"""
|
|
758
826
|
alias_value = payload.pop(alias_key, None)
|
|
759
827
|
if canonical_key not in payload and alias_value is not None:
|
|
760
828
|
payload[canonical_key] = alias_value
|
|
@@ -762,6 +830,7 @@ class ApprovalTools(ToolBase):
|
|
|
762
830
|
raise_tool_error(QingflowApiError.config_error(f"payload.{canonical_key} and payload.{alias_key} must match when both are provided"))
|
|
763
831
|
|
|
764
832
|
def _resolve_actionable_node_id(self, context, app_key: str, apply_id: int, node_id: int) -> int: # type: ignore[no-untyped-def]
|
|
833
|
+
"""执行内部辅助逻辑。"""
|
|
765
834
|
infos = self.backend.request(
|
|
766
835
|
"GET",
|
|
767
836
|
context,
|
|
@@ -790,6 +859,7 @@ class ApprovalTools(ToolBase):
|
|
|
790
859
|
return node_id
|
|
791
860
|
|
|
792
861
|
def _fetch_current_todo_answers(self, context, app_key: str, apply_id: int, node_id: int) -> list[dict[str, Any]]: # type: ignore[no-untyped-def]
|
|
862
|
+
"""执行内部辅助逻辑。"""
|
|
793
863
|
detail = self.backend.request(
|
|
794
864
|
"GET",
|
|
795
865
|
context,
|
|
@@ -810,6 +880,7 @@ class ApprovalTools(ToolBase):
|
|
|
810
880
|
return normalized_answers
|
|
811
881
|
|
|
812
882
|
def _validate_approval_payload(self, payload: dict[str, Any]) -> None:
|
|
883
|
+
"""执行内部辅助逻辑。"""
|
|
813
884
|
self._reject_unsupported_fields(payload)
|
|
814
885
|
if not isinstance(payload.get("formId"), int) or payload["formId"] <= 0:
|
|
815
886
|
raise_tool_error(QingflowApiError.config_error("payload.formId must be a positive integer"))
|
|
@@ -822,21 +893,25 @@ class ApprovalTools(ToolBase):
|
|
|
822
893
|
raise_tool_error(QingflowApiError.config_error("payload.answers must be an array when provided"))
|
|
823
894
|
|
|
824
895
|
def _validate_audit_payload(self, payload: dict[str, Any], *, require_uid: bool = False) -> None:
|
|
896
|
+
"""执行内部辅助逻辑。"""
|
|
825
897
|
self._reject_unsupported_fields(payload)
|
|
826
898
|
if require_uid and not payload.get("uid"):
|
|
827
899
|
raise_tool_error(QingflowApiError.config_error("payload.uid is required"))
|
|
828
900
|
|
|
829
901
|
def _validate_countersign_payload(self, payload: dict[str, Any]) -> None:
|
|
902
|
+
"""执行内部辅助逻辑。"""
|
|
830
903
|
self._reject_unsupported_fields(payload)
|
|
831
904
|
members = payload.get("countersignMembers")
|
|
832
905
|
if not isinstance(members, list) or not members:
|
|
833
906
|
raise_tool_error(QingflowApiError.config_error("payload.countersignMembers must be a non-empty array"))
|
|
834
907
|
|
|
835
908
|
def _reject_unsupported_fields(self, payload: dict[str, Any]) -> None:
|
|
909
|
+
"""执行内部辅助逻辑。"""
|
|
836
910
|
if payload.get("handSignImageUrl"):
|
|
837
911
|
raise_tool_error(QingflowApiError.not_supported("NOT_SUPPORTED_IN_V1: handSignImageUrl is not supported"))
|
|
838
912
|
|
|
839
913
|
def _extract_transfer_target_uid(self, payload: dict[str, Any]) -> int | None:
|
|
914
|
+
"""执行内部辅助逻辑。"""
|
|
840
915
|
for key in ("uid", "target_member_id", "targetMemberId"):
|
|
841
916
|
value = payload.get(key)
|
|
842
917
|
if isinstance(value, int) and value > 0:
|
|
@@ -844,6 +919,7 @@ class ApprovalTools(ToolBase):
|
|
|
844
919
|
return None
|
|
845
920
|
|
|
846
921
|
def _raise_if_self_transfer(self, *, profile: str, payload: dict[str, Any]) -> None:
|
|
922
|
+
"""执行内部辅助逻辑。"""
|
|
847
923
|
target_uid = self._extract_transfer_target_uid(payload)
|
|
848
924
|
if target_uid is None:
|
|
849
925
|
return
|
|
@@ -856,6 +932,7 @@ class ApprovalTools(ToolBase):
|
|
|
856
932
|
)
|
|
857
933
|
|
|
858
934
|
def _filter_self_transfer_candidates(self, *, profile: str, items: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
935
|
+
"""执行内部辅助逻辑。"""
|
|
859
936
|
session_profile = self.sessions.get_profile(profile)
|
|
860
937
|
if session_profile is None:
|
|
861
938
|
return items
|
|
@@ -874,6 +951,7 @@ class ApprovalTools(ToolBase):
|
|
|
874
951
|
public_action: str,
|
|
875
952
|
workflow_node_id: int | None = None,
|
|
876
953
|
) -> dict[str, Any]:
|
|
954
|
+
"""执行内部辅助逻辑。"""
|
|
877
955
|
from .task_context_tools import TaskContextTools
|
|
878
956
|
|
|
879
957
|
node_id = workflow_node_id
|
|
@@ -905,6 +983,7 @@ class ApprovalTools(ToolBase):
|
|
|
905
983
|
pagination: dict[str, Any],
|
|
906
984
|
selection: dict[str, Any],
|
|
907
985
|
) -> dict[str, Any]:
|
|
986
|
+
"""执行内部辅助逻辑。"""
|
|
908
987
|
response = dict(raw)
|
|
909
988
|
response["ok"] = bool(raw.get("ok", True))
|
|
910
989
|
response["warnings"] = []
|
|
@@ -925,6 +1004,7 @@ class ApprovalTools(ToolBase):
|
|
|
925
1004
|
selection: dict[str, Any],
|
|
926
1005
|
human_review: bool = False,
|
|
927
1006
|
) -> dict[str, Any]:
|
|
1007
|
+
"""执行内部辅助逻辑。"""
|
|
928
1008
|
response = dict(raw)
|
|
929
1009
|
response["ok"] = bool(raw.get("ok", True))
|
|
930
1010
|
response["warnings"] = []
|
|
@@ -939,6 +1019,7 @@ class ApprovalTools(ToolBase):
|
|
|
939
1019
|
return response
|
|
940
1020
|
|
|
941
1021
|
def _request_route_payload(self, context) -> JSONObject: # type: ignore[no-untyped-def]
|
|
1022
|
+
"""执行内部辅助逻辑。"""
|
|
942
1023
|
describe_route = getattr(self.backend, "describe_route", None)
|
|
943
1024
|
if callable(describe_route):
|
|
944
1025
|
payload = describe_route(context)
|