@josephyan/qingflow-cli 0.2.0-beta.988 → 0.2.0-beta.990

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.
@@ -10,6 +10,7 @@ from mcp.server.fastmcp import FastMCP
10
10
  from ..backend_client import BackendRequestContext
11
11
  from ..config import DEFAULT_PROFILE
12
12
  from ..errors import QingflowApiError, raise_tool_error
13
+ from ..id_utils import ids_equal, normalize_positive_id_int, stringify_backend_id
13
14
  from ..json_types import JSONObject
14
15
  from .approval_tools import ApprovalTools, _approval_page_amount, _approval_page_items, _approval_page_total
15
16
  from .base import ToolBase, tool_cn_name
@@ -87,7 +88,7 @@ class TaskContextTools(ToolBase):
87
88
  def task_get(
88
89
  profile: str = DEFAULT_PROFILE,
89
90
  app_key: str = "",
90
- record_id: int = 0,
91
+ record_id: str = "",
91
92
  workflow_node_id: int = 0,
92
93
  include_candidates: bool = True,
93
94
  include_associated_reports: bool = True,
@@ -105,7 +106,7 @@ class TaskContextTools(ToolBase):
105
106
  def task_action_execute(
106
107
  profile: str = DEFAULT_PROFILE,
107
108
  app_key: str = "",
108
- record_id: int = 0,
109
+ record_id: str = "",
109
110
  workflow_node_id: int = 0,
110
111
  action: str = "",
111
112
  payload: dict[str, Any] | None = None,
@@ -125,7 +126,7 @@ class TaskContextTools(ToolBase):
125
126
  def task_associated_report_detail_get(
126
127
  profile: str = DEFAULT_PROFILE,
127
128
  app_key: str = "",
128
- record_id: int = 0,
129
+ record_id: str = "",
129
130
  workflow_node_id: int = 0,
130
131
  report_id: int = 0,
131
132
  page: int = 1,
@@ -145,7 +146,7 @@ class TaskContextTools(ToolBase):
145
146
  def task_workflow_log_get(
146
147
  profile: str = DEFAULT_PROFILE,
147
148
  app_key: str = "",
148
- record_id: int = 0,
149
+ record_id: str = "",
149
150
  workflow_node_id: int = 0,
150
151
  ) -> dict[str, Any]:
151
152
  return self.task_workflow_log_get(
@@ -249,20 +250,21 @@ class TaskContextTools(ToolBase):
249
250
  *,
250
251
  profile: str,
251
252
  app_key: str,
252
- record_id: int,
253
+ record_id: Any,
253
254
  workflow_node_id: int,
254
255
  include_candidates: bool,
255
256
  include_associated_reports: bool,
256
257
  ) -> dict[str, Any]:
257
258
  """执行任务相关逻辑。"""
258
- self._require_app_record_and_node(app_key, record_id, workflow_node_id)
259
+ record_id_int = normalize_positive_id_int(record_id, field_name="record_id")
260
+ self._require_app_record_and_node(app_key, record_id_int, workflow_node_id)
259
261
 
260
262
  def runner(session_profile, context):
261
263
  data = self._build_task_context(
262
264
  profile=profile,
263
265
  context=context,
264
266
  app_key=app_key,
265
- record_id=record_id,
267
+ record_id=record_id_int,
266
268
  workflow_node_id=workflow_node_id,
267
269
  include_candidates=include_candidates,
268
270
  include_associated_reports=include_associated_reports,
@@ -287,7 +289,7 @@ class TaskContextTools(ToolBase):
287
289
  *,
288
290
  profile: str,
289
291
  app_key: str,
290
- record_id: int,
292
+ record_id: Any,
291
293
  workflow_node_id: int,
292
294
  fields: dict[str, Any] | None = None,
293
295
  ) -> dict[str, Any]:
@@ -311,14 +313,16 @@ class TaskContextTools(ToolBase):
311
313
  *,
312
314
  profile: str,
313
315
  app_key: str,
314
- record_id: int,
316
+ record_id: Any,
315
317
  workflow_node_id: int,
316
318
  action: str,
317
319
  payload: dict[str, Any],
318
320
  fields: dict[str, Any] | None = None,
319
321
  ) -> dict[str, Any]:
320
322
  """执行任务相关逻辑。"""
321
- self._require_app_record_and_node(app_key, record_id, workflow_node_id)
323
+ record_id_int = normalize_positive_id_int(record_id, field_name="record_id")
324
+ record_id_text = stringify_backend_id(record_id_int)
325
+ self._require_app_record_and_node(app_key, record_id_int, workflow_node_id)
322
326
  normalized_action = (action or "").strip().lower()
323
327
  if normalized_action not in {"approve", "reject", "rollback", "transfer", "urge", "save_only"}:
324
328
  raise_tool_error(
@@ -341,7 +345,7 @@ class TaskContextTools(ToolBase):
341
345
  profile=profile,
342
346
  context=context,
343
347
  app_key=app_key,
344
- record_id=record_id,
348
+ record_id=record_id_int,
345
349
  workflow_node_id=workflow_node_id,
346
350
  include_candidates=False,
347
351
  include_associated_reports=False,
@@ -354,7 +358,7 @@ class TaskContextTools(ToolBase):
354
358
  session_profile=session_profile,
355
359
  context=context,
356
360
  app_key=app_key,
357
- record_id=record_id,
361
+ record_id=record_id_int,
358
362
  workflow_node_id=workflow_node_id,
359
363
  action=normalized_action,
360
364
  source_error=error,
@@ -387,7 +391,7 @@ class TaskContextTools(ToolBase):
387
391
  raise_tool_error(QingflowApiError.config_error(message))
388
392
  raise_tool_error(
389
393
  QingflowApiError.config_error(
390
- f"task action '{normalized_action}' is not currently available for app_key='{app_key}' record_id={record_id} workflow_node_id={workflow_node_id}"
394
+ f"task action '{normalized_action}' is not currently available for app_key='{app_key}' record_id={record_id_text} workflow_node_id={workflow_node_id}"
391
395
  )
392
396
  )
393
397
  feedback_required_for = capabilities.get("action_constraints", {}).get("feedback_required_for") or []
@@ -409,7 +413,7 @@ class TaskContextTools(ToolBase):
409
413
  profile=profile,
410
414
  context=context,
411
415
  app_key=app_key,
412
- record_id=record_id,
416
+ record_id=record_id_int,
413
417
  workflow_node_id=workflow_node_id,
414
418
  task_context=task_context,
415
419
  fields=field_updates,
@@ -421,14 +425,14 @@ class TaskContextTools(ToolBase):
421
425
  profile=profile,
422
426
  context=context,
423
427
  app_key=app_key,
424
- record_id=record_id,
428
+ record_id=record_id_int,
425
429
  workflow_node_id=workflow_node_id,
426
430
  )
427
431
  try:
428
432
  raw = self._execute_task_action(
429
433
  profile=profile,
430
434
  app_key=app_key,
431
- record_id=record_id,
435
+ record_id=record_id_int,
432
436
  workflow_node_id=workflow_node_id,
433
437
  normalized_action=normalized_action,
434
438
  payload=body,
@@ -441,7 +445,7 @@ class TaskContextTools(ToolBase):
441
445
  session_profile=session_profile,
442
446
  context=context,
443
447
  app_key=app_key,
444
- record_id=record_id,
448
+ record_id=record_id_int,
445
449
  workflow_node_id=workflow_node_id,
446
450
  action=normalized_action,
447
451
  source_error=error,
@@ -453,7 +457,7 @@ class TaskContextTools(ToolBase):
453
457
  verification, warnings = self._verify_task_save_only(
454
458
  context=context,
455
459
  app_key=app_key,
456
- record_id=record_id,
460
+ record_id=record_id_int,
457
461
  workflow_node_id=workflow_node_id,
458
462
  before_apply_status=before_apply_status,
459
463
  expected_answers=((prepared_fields or {}).get("normalized_answers") or []),
@@ -467,7 +471,7 @@ class TaskContextTools(ToolBase):
467
471
  profile=profile,
468
472
  context=context,
469
473
  app_key=app_key,
470
- record_id=record_id,
474
+ record_id=record_id_int,
471
475
  workflow_node_id=workflow_node_id,
472
476
  action=normalized_action,
473
477
  before_apply_status=before_apply_status,
@@ -490,7 +494,7 @@ class TaskContextTools(ToolBase):
490
494
  "action": normalized_action,
491
495
  "resource": {
492
496
  "app_key": app_key,
493
- "record_id": record_id,
497
+ "record_id": record_id_text,
494
498
  "workflow_node_id": workflow_node_id,
495
499
  },
496
500
  "selection": {"action": normalized_action},
@@ -507,7 +511,7 @@ class TaskContextTools(ToolBase):
507
511
  *,
508
512
  profile: str,
509
513
  app_key: str,
510
- record_id: int,
514
+ record_id: Any,
511
515
  workflow_node_id: int,
512
516
  normalized_action: str,
513
517
  payload: dict[str, Any],
@@ -671,12 +675,12 @@ class TaskContextTools(ToolBase):
671
675
  todo_items = self._safe_task_list_items(profile=profile, task_box="todo", app_key=app_key)
672
676
  initiated_items = self._safe_task_list_items(profile=profile, task_box="initiated", app_key=app_key)
673
677
  downstream_todo_detected = any(
674
- int(item.get("record_id") or 0) == record_id and int(item.get("workflow_node_id") or 0) != workflow_node_id
678
+ ids_equal(item.get("record_id"), record_id) and int(item.get("workflow_node_id") or 0) != workflow_node_id
675
679
  for item in todo_items
676
680
  if isinstance(item, dict)
677
681
  )
678
682
  initiated_visible = any(
679
- int(item.get("record_id") or 0) == record_id
683
+ ids_equal(item.get("record_id"), record_id)
680
684
  for item in initiated_items
681
685
  if isinstance(item, dict)
682
686
  )
@@ -693,7 +697,7 @@ class TaskContextTools(ToolBase):
693
697
  int(item.get("workflow_node_id") or 0)
694
698
  for item in todo_items
695
699
  if isinstance(item, dict)
696
- and int(item.get("record_id") or 0) == record_id
700
+ and ids_equal(item.get("record_id"), record_id)
697
701
  and int(item.get("workflow_node_id") or 0) != workflow_node_id
698
702
  }
699
703
  workflow_log_digest = self._workflow_log_digest(log_items)
@@ -898,7 +902,7 @@ class TaskContextTools(ToolBase):
898
902
  int(item.get("workflow_node_id") or 0)
899
903
  for item in todo_items
900
904
  if isinstance(item, dict)
901
- and int(item.get("record_id") or 0) == record_id
905
+ and ids_equal(item.get("record_id"), record_id)
902
906
  and int(item.get("workflow_node_id") or 0) != workflow_node_id
903
907
  }
904
908
  )
@@ -918,6 +922,7 @@ class TaskContextTools(ToolBase):
918
922
  before_apply_status: Any,
919
923
  ) -> dict[str, Any]:
920
924
  """执行内部辅助逻辑。"""
925
+ record_id_text = stringify_backend_id(record_id)
921
926
  verification, warnings = self._verify_task_action_runtime(
922
927
  profile=profile,
923
928
  context=context,
@@ -950,7 +955,7 @@ class TaskContextTools(ToolBase):
950
955
  "action": action,
951
956
  "resource": {
952
957
  "app_key": app_key,
953
- "record_id": record_id,
958
+ "record_id": record_id_text,
954
959
  "workflow_node_id": workflow_node_id,
955
960
  },
956
961
  "selection": {"action": action},
@@ -978,7 +983,7 @@ class TaskContextTools(ToolBase):
978
983
  "action": action,
979
984
  "resource": {
980
985
  "app_key": app_key,
981
- "record_id": record_id,
986
+ "record_id": record_id_text,
982
987
  "workflow_node_id": workflow_node_id,
983
988
  },
984
989
  "selection": {"action": action},
@@ -1101,7 +1106,9 @@ class TaskContextTools(ToolBase):
1101
1106
  page_size: int,
1102
1107
  ) -> dict[str, Any]:
1103
1108
  """执行任务相关逻辑。"""
1104
- self._require_app_record_and_node(app_key, record_id, workflow_node_id)
1109
+ record_id_int = normalize_positive_id_int(record_id, field_name="record_id")
1110
+ record_id_text = stringify_backend_id(record_id_int)
1111
+ self._require_app_record_and_node(app_key, record_id_int, workflow_node_id)
1105
1112
  if report_id <= 0:
1106
1113
  raise_tool_error(QingflowApiError.config_error("report_id must be positive"))
1107
1114
  if page <= 0 or page_size <= 0:
@@ -1112,7 +1119,7 @@ class TaskContextTools(ToolBase):
1112
1119
  profile=profile,
1113
1120
  context=context,
1114
1121
  app_key=app_key,
1115
- record_id=record_id,
1122
+ record_id=record_id_int,
1116
1123
  workflow_node_id=workflow_node_id,
1117
1124
  include_candidates=False,
1118
1125
  include_associated_reports=True,
@@ -1122,7 +1129,7 @@ class TaskContextTools(ToolBase):
1122
1129
  if report_item is None:
1123
1130
  raise_tool_error(
1124
1131
  QingflowApiError.config_error(
1125
- f"report_id={report_id} is not visible for app_key='{app_key}' record_id={record_id} workflow_node_id={workflow_node_id}"
1132
+ f"report_id={report_id} is not visible for app_key='{app_key}' record_id={record_id_text} workflow_node_id={workflow_node_id}"
1126
1133
  )
1127
1134
  )
1128
1135
  association_query = self._build_association_query(
@@ -1131,7 +1138,7 @@ class TaskContextTools(ToolBase):
1131
1138
  )
1132
1139
  selection = {
1133
1140
  "app_key": app_key,
1134
- "record_id": record_id,
1141
+ "record_id": record_id_text,
1135
1142
  "workflow_node_id": workflow_node_id,
1136
1143
  "report_id": report_id,
1137
1144
  "target_app_key": report_item.get("target_app_key"),
@@ -1286,18 +1293,20 @@ class TaskContextTools(ToolBase):
1286
1293
  *,
1287
1294
  profile: str,
1288
1295
  app_key: str,
1289
- record_id: int,
1296
+ record_id: Any,
1290
1297
  workflow_node_id: int,
1291
1298
  ) -> dict[str, Any]:
1292
1299
  """执行任务相关逻辑。"""
1293
- self._require_app_record_and_node(app_key, record_id, workflow_node_id)
1300
+ record_id_int = normalize_positive_id_int(record_id, field_name="record_id")
1301
+ record_id_text = stringify_backend_id(record_id_int)
1302
+ self._require_app_record_and_node(app_key, record_id_int, workflow_node_id)
1294
1303
 
1295
1304
  def runner(session_profile, context):
1296
1305
  task_context = self._build_task_context(
1297
1306
  profile=profile,
1298
1307
  context=context,
1299
1308
  app_key=app_key,
1300
- record_id=record_id,
1309
+ record_id=record_id_int,
1301
1310
  workflow_node_id=workflow_node_id,
1302
1311
  include_candidates=False,
1303
1312
  include_associated_reports=False,
@@ -1307,7 +1316,7 @@ class TaskContextTools(ToolBase):
1307
1316
  if not visibility.get("audit_record_visible"):
1308
1317
  raise_tool_error(
1309
1318
  QingflowApiError.config_error(
1310
- f"workflow logs are not visible for app_key='{app_key}' record_id={record_id} workflow_node_id={workflow_node_id}"
1319
+ f"workflow logs are not visible for app_key='{app_key}' record_id={record_id_text} workflow_node_id={workflow_node_id}"
1311
1320
  )
1312
1321
  )
1313
1322
  page = self.backend.request(
@@ -1316,7 +1325,7 @@ class TaskContextTools(ToolBase):
1316
1325
  "/application/workflow/node/record",
1317
1326
  json_body={
1318
1327
  "key": app_key,
1319
- "rowRecordId": record_id,
1328
+ "rowRecordId": record_id_int,
1320
1329
  "nodeId": workflow_node_id,
1321
1330
  "role": 3,
1322
1331
  "pageNum": 1,
@@ -1334,7 +1343,7 @@ class TaskContextTools(ToolBase):
1334
1343
  "data": {
1335
1344
  "selection": {
1336
1345
  "app_key": app_key,
1337
- "record_id": record_id,
1346
+ "record_id": record_id_text,
1338
1347
  "workflow_node_id": workflow_node_id,
1339
1348
  },
1340
1349
  "visibility": {
@@ -1443,11 +1452,12 @@ class TaskContextTools(ToolBase):
1443
1452
  save_only_source=save_only_source,
1444
1453
  )
1445
1454
  visibility = self._build_visibility(node_info, detail)
1455
+ record_id_text = stringify_backend_id(record_id)
1446
1456
  return {
1447
1457
  "task": {
1448
1458
  "app_key": app_key,
1449
1459
  "app_name": app_name,
1450
- "record_id": record_id,
1460
+ "record_id": record_id_text,
1451
1461
  "workflow_node_id": workflow_node_id,
1452
1462
  "workflow_node_name": node_info.get("auditNodeName") or node_info.get("nodeName"),
1453
1463
  "actionable": True,
@@ -1458,7 +1468,7 @@ class TaskContextTools(ToolBase):
1458
1468
  "raw": dict(node_info),
1459
1469
  },
1460
1470
  "record": {
1461
- "apply_id": detail.get("applyId", record_id),
1471
+ "apply_id": stringify_backend_id(detail.get("applyId") or record_id),
1462
1472
  "apply_status": detail.get("applyStatus"),
1463
1473
  "apply_num": detail.get("applyNum"),
1464
1474
  "custom_apply_num": detail.get("customApplyNum"),
@@ -1526,7 +1536,7 @@ class TaskContextTools(ToolBase):
1526
1536
  "task": {
1527
1537
  "app_key": task.get("app_key"),
1528
1538
  "app_name": task.get("app_name"),
1529
- "record_id": task.get("record_id"),
1539
+ "record_id": stringify_backend_id(task.get("record_id")),
1530
1540
  "workflow_node_id": task.get("workflow_node_id"),
1531
1541
  "workflow_node_name": task.get("workflow_node_name"),
1532
1542
  "initiator": self._compact_initiator(record.get("apply_user")),
@@ -1722,10 +1732,10 @@ class TaskContextTools(ToolBase):
1722
1732
  record_id = raw.get("rowRecordId") or raw.get("recordId") or raw.get("applyId")
1723
1733
  workflow_node_id = raw.get("nodeId") or raw.get("auditNodeId")
1724
1734
  return {
1725
- "task_id": raw.get("id") or raw.get("taskId") or record_id,
1735
+ "task_id": stringify_backend_id(raw.get("id") or raw.get("taskId") or record_id),
1726
1736
  "app_key": app_key,
1727
1737
  "app_name": raw.get("formTitle") or raw.get("worksheetName") or raw.get("appName"),
1728
- "record_id": record_id,
1738
+ "record_id": stringify_backend_id(record_id),
1729
1739
  "workflow_node_id": workflow_node_id,
1730
1740
  "workflow_node_name": raw.get("nodeName") or raw.get("auditNodeName"),
1731
1741
  "apply_time": raw.get("applyTime") or raw.get("receiveTime"),
@@ -1816,6 +1826,7 @@ class TaskContextTools(ToolBase):
1816
1826
  current_answers: Any,
1817
1827
  ) -> dict[str, Any]:
1818
1828
  """执行内部辅助逻辑。"""
1829
+ record_id_text = stringify_backend_id(record_id)
1819
1830
  try:
1820
1831
  app_schema = self._record_tools._get_form_schema(profile, context, app_key, force_refresh=False)
1821
1832
  except QingflowApiError as error:
@@ -1832,7 +1843,7 @@ class TaskContextTools(ToolBase):
1832
1843
  ],
1833
1844
  "selection": {
1834
1845
  "app_key": app_key,
1835
- "record_id": record_id,
1846
+ "record_id": record_id_text,
1836
1847
  "workflow_node_id": workflow_node_id,
1837
1848
  },
1838
1849
  "transport_error": {
@@ -1917,7 +1928,7 @@ class TaskContextTools(ToolBase):
1917
1928
  "warnings": schema_warnings,
1918
1929
  "selection": {
1919
1930
  "app_key": app_key,
1920
- "record_id": record_id,
1931
+ "record_id": record_id_text,
1921
1932
  "workflow_node_id": workflow_node_id,
1922
1933
  },
1923
1934
  }