@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.
- package/README.md +2 -2
- package/docs/local-agent-install.md +7 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/cli/commands/auth.py +128 -0
- package/src/qingflow_mcp/cli/commands/record.py +5 -5
- package/src/qingflow_mcp/cli/commands/task.py +3 -3
- package/src/qingflow_mcp/cli/formatters.py +7 -0
- package/src/qingflow_mcp/cli/oauth_login.py +626 -0
- package/src/qingflow_mcp/cli/qingflow_login.py +116 -0
- package/src/qingflow_mcp/errors.py +2 -2
- package/src/qingflow_mcp/id_utils.py +49 -0
- package/src/qingflow_mcp/public_surface.py +1 -0
- package/src/qingflow_mcp/response_trim.py +10 -0
- package/src/qingflow_mcp/tools/auth_tools.py +130 -0
- package/src/qingflow_mcp/tools/base.py +1 -1
- package/src/qingflow_mcp/tools/code_block_tools.py +2 -2
- package/src/qingflow_mcp/tools/record_tools.py +96 -55
- package/src/qingflow_mcp/tools/task_context_tools.py +55 -44
|
@@ -13,6 +13,7 @@ from mcp.server.fastmcp import FastMCP
|
|
|
13
13
|
|
|
14
14
|
from ..config import DEFAULT_PROFILE, DEFAULT_RECORD_LIST_TYPE
|
|
15
15
|
from ..errors import QingflowApiError, raise_tool_error
|
|
16
|
+
from ..id_utils import normalize_positive_id_int, stringify_backend_id
|
|
16
17
|
from ..json_types import JSONObject, JSONScalar, JSONValue
|
|
17
18
|
from ..list_type_labels import (
|
|
18
19
|
SYSTEM_VIEW_DEFINITIONS,
|
|
@@ -284,7 +285,7 @@ class RecordTools(ToolBase):
|
|
|
284
285
|
profile: str = DEFAULT_PROFILE,
|
|
285
286
|
app_key: str = "",
|
|
286
287
|
field_id: int = 0,
|
|
287
|
-
record_id:
|
|
288
|
+
record_id: str | None = None,
|
|
288
289
|
workflow_node_id: int | None = None,
|
|
289
290
|
fields: JSONObject | None = None,
|
|
290
291
|
keyword: str = "",
|
|
@@ -315,7 +316,7 @@ class RecordTools(ToolBase):
|
|
|
315
316
|
profile: str = DEFAULT_PROFILE,
|
|
316
317
|
app_key: str = "",
|
|
317
318
|
field_id: int = 0,
|
|
318
|
-
record_id:
|
|
319
|
+
record_id: str | None = None,
|
|
319
320
|
workflow_node_id: int | None = None,
|
|
320
321
|
fields: JSONObject | None = None,
|
|
321
322
|
keyword: str = "",
|
|
@@ -407,7 +408,7 @@ class RecordTools(ToolBase):
|
|
|
407
408
|
def record_get(
|
|
408
409
|
profile: str = DEFAULT_PROFILE,
|
|
409
410
|
app_key: str = "",
|
|
410
|
-
record_id:
|
|
411
|
+
record_id: str = "",
|
|
411
412
|
columns: list[JSONObject | int] | None = None,
|
|
412
413
|
view_id: str | None = None,
|
|
413
414
|
workflow_node_id: int | None = None,
|
|
@@ -439,7 +440,7 @@ class RecordTools(ToolBase):
|
|
|
439
440
|
@mcp.tool()
|
|
440
441
|
def record_update_schema_get(
|
|
441
442
|
app_key: str = "",
|
|
442
|
-
record_id:
|
|
443
|
+
record_id: str = "",
|
|
443
444
|
output_profile: str = "normal",
|
|
444
445
|
) -> JSONObject:
|
|
445
446
|
return self.record_update_schema_get_public(
|
|
@@ -479,7 +480,7 @@ class RecordTools(ToolBase):
|
|
|
479
480
|
)
|
|
480
481
|
def record_update(
|
|
481
482
|
app_key: str = "",
|
|
482
|
-
record_id:
|
|
483
|
+
record_id: str | None = None,
|
|
483
484
|
fields: JSONObject | None = None,
|
|
484
485
|
items: list[JSONObject] | None = None,
|
|
485
486
|
dry_run: bool = False,
|
|
@@ -505,8 +506,8 @@ class RecordTools(ToolBase):
|
|
|
505
506
|
)
|
|
506
507
|
def record_delete(
|
|
507
508
|
app_key: str = "",
|
|
508
|
-
record_id:
|
|
509
|
-
record_ids: list[
|
|
509
|
+
record_id: str | None = None,
|
|
510
|
+
record_ids: list[str] | None = None,
|
|
510
511
|
output_profile: str = "normal",
|
|
511
512
|
) -> JSONObject:
|
|
512
513
|
return self.record_delete_public(
|
|
@@ -784,14 +785,13 @@ class RecordTools(ToolBase):
|
|
|
784
785
|
*,
|
|
785
786
|
profile: str = DEFAULT_PROFILE,
|
|
786
787
|
app_key: str,
|
|
787
|
-
record_id:
|
|
788
|
+
record_id: Any,
|
|
788
789
|
output_profile: str = "normal",
|
|
789
790
|
) -> JSONObject:
|
|
790
791
|
"""执行记录相关逻辑。"""
|
|
791
792
|
if not app_key:
|
|
792
793
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
793
|
-
|
|
794
|
-
raise_tool_error(QingflowApiError.config_error("record_id is required"))
|
|
794
|
+
record_id_int = normalize_positive_id_int(record_id, field_name="record_id")
|
|
795
795
|
normalized_output_profile = self._normalize_public_output_profile(output_profile)
|
|
796
796
|
|
|
797
797
|
def runner(session_profile, context):
|
|
@@ -815,7 +815,7 @@ class RecordTools(ToolBase):
|
|
|
815
815
|
probes = self._probe_candidate_record_contexts(
|
|
816
816
|
context,
|
|
817
817
|
app_key=app_key,
|
|
818
|
-
apply_id=
|
|
818
|
+
apply_id=record_id_int,
|
|
819
819
|
candidate_routes=candidate_routes,
|
|
820
820
|
)
|
|
821
821
|
probe_summary: list[JSONObject] = []
|
|
@@ -906,7 +906,7 @@ class RecordTools(ToolBase):
|
|
|
906
906
|
ws_id=ws_id,
|
|
907
907
|
request_route=request_route,
|
|
908
908
|
app_key=app_key,
|
|
909
|
-
record_id=
|
|
909
|
+
record_id=record_id_int,
|
|
910
910
|
blockers=blockers,
|
|
911
911
|
warnings=warnings,
|
|
912
912
|
recommended_next_actions=recommended_next_actions,
|
|
@@ -949,7 +949,7 @@ class RecordTools(ToolBase):
|
|
|
949
949
|
ws_id=ws_id,
|
|
950
950
|
request_route=request_route,
|
|
951
951
|
app_key=app_key,
|
|
952
|
-
record_id=
|
|
952
|
+
record_id=record_id_int,
|
|
953
953
|
blockers=["NO_WRITABLE_FIELDS_FOR_RECORD"],
|
|
954
954
|
warnings=[item["message"] for item in warnings if isinstance(item.get("message"), str)],
|
|
955
955
|
recommended_next_actions=[
|
|
@@ -969,7 +969,7 @@ class RecordTools(ToolBase):
|
|
|
969
969
|
"request_route": request_route,
|
|
970
970
|
"warnings": warnings,
|
|
971
971
|
"app_key": app_key,
|
|
972
|
-
"record_id":
|
|
972
|
+
"record_id": stringify_backend_id(record_id_int),
|
|
973
973
|
"schema_scope": "update_ready",
|
|
974
974
|
"writable_fields": writable_fields,
|
|
975
975
|
"payload_template": {
|
|
@@ -1009,7 +1009,7 @@ class RecordTools(ToolBase):
|
|
|
1009
1009
|
"request_route": request_route,
|
|
1010
1010
|
"warnings": [{"code": "PREFLIGHT_WARNING", "message": item} for item in warnings],
|
|
1011
1011
|
"app_key": app_key,
|
|
1012
|
-
"record_id": record_id,
|
|
1012
|
+
"record_id": stringify_backend_id(record_id),
|
|
1013
1013
|
"schema_scope": "update_ready",
|
|
1014
1014
|
"blockers": blockers,
|
|
1015
1015
|
"writable_fields": [],
|
|
@@ -1281,7 +1281,7 @@ class RecordTools(ToolBase):
|
|
|
1281
1281
|
profile: str,
|
|
1282
1282
|
app_key: str,
|
|
1283
1283
|
field_id: int,
|
|
1284
|
-
record_id:
|
|
1284
|
+
record_id: Any | None = None,
|
|
1285
1285
|
workflow_node_id: int | None = None,
|
|
1286
1286
|
fields: JSONObject | None = None,
|
|
1287
1287
|
keyword: str,
|
|
@@ -1297,6 +1297,12 @@ class RecordTools(ToolBase):
|
|
|
1297
1297
|
raise_tool_error(QingflowApiError.config_error("page_num must be positive"))
|
|
1298
1298
|
if page_size <= 0:
|
|
1299
1299
|
raise_tool_error(QingflowApiError.config_error("page_size must be positive"))
|
|
1300
|
+
record_id_int = (
|
|
1301
|
+
normalize_positive_id_int(record_id, field_name="record_id")
|
|
1302
|
+
if record_id is not None
|
|
1303
|
+
else None
|
|
1304
|
+
)
|
|
1305
|
+
record_id_text = stringify_backend_id(record_id_int) if record_id_int is not None else None
|
|
1300
1306
|
|
|
1301
1307
|
def runner(session_profile, context):
|
|
1302
1308
|
index = self._get_field_index(profile, context, app_key, force_refresh=False)
|
|
@@ -1316,7 +1322,7 @@ class RecordTools(ToolBase):
|
|
|
1316
1322
|
)
|
|
1317
1323
|
normalized_fields = fields if isinstance(fields, dict) else {}
|
|
1318
1324
|
runtime_lookup = self._candidate_lookup_uses_runtime_scope(
|
|
1319
|
-
record_id=
|
|
1325
|
+
record_id=record_id_int,
|
|
1320
1326
|
workflow_node_id=workflow_node_id,
|
|
1321
1327
|
fields=normalized_fields,
|
|
1322
1328
|
)
|
|
@@ -1327,7 +1333,7 @@ class RecordTools(ToolBase):
|
|
|
1327
1333
|
profile,
|
|
1328
1334
|
context,
|
|
1329
1335
|
app_key=app_key,
|
|
1330
|
-
record_id=
|
|
1336
|
+
record_id=record_id_int,
|
|
1331
1337
|
workflow_node_id=workflow_node_id,
|
|
1332
1338
|
fields=normalized_fields,
|
|
1333
1339
|
)
|
|
@@ -1366,7 +1372,7 @@ class RecordTools(ToolBase):
|
|
|
1366
1372
|
"app_key": app_key,
|
|
1367
1373
|
"field_id": field.que_id,
|
|
1368
1374
|
"field_title": field.que_title,
|
|
1369
|
-
"record_id":
|
|
1375
|
+
"record_id": record_id_text,
|
|
1370
1376
|
"workflow_node_id": workflow_node_id,
|
|
1371
1377
|
"fields_present": bool(normalized_fields),
|
|
1372
1378
|
"keyword": keyword,
|
|
@@ -1385,7 +1391,7 @@ class RecordTools(ToolBase):
|
|
|
1385
1391
|
profile: str,
|
|
1386
1392
|
app_key: str,
|
|
1387
1393
|
field_id: int,
|
|
1388
|
-
record_id:
|
|
1394
|
+
record_id: Any | None = None,
|
|
1389
1395
|
workflow_node_id: int | None = None,
|
|
1390
1396
|
fields: JSONObject | None = None,
|
|
1391
1397
|
keyword: str,
|
|
@@ -1401,6 +1407,12 @@ class RecordTools(ToolBase):
|
|
|
1401
1407
|
raise_tool_error(QingflowApiError.config_error("page_num must be positive"))
|
|
1402
1408
|
if page_size <= 0:
|
|
1403
1409
|
raise_tool_error(QingflowApiError.config_error("page_size must be positive"))
|
|
1410
|
+
record_id_int = (
|
|
1411
|
+
normalize_positive_id_int(record_id, field_name="record_id")
|
|
1412
|
+
if record_id is not None
|
|
1413
|
+
else None
|
|
1414
|
+
)
|
|
1415
|
+
record_id_text = stringify_backend_id(record_id_int) if record_id_int is not None else None
|
|
1404
1416
|
|
|
1405
1417
|
def runner(session_profile, context):
|
|
1406
1418
|
index = self._get_field_index(profile, context, app_key, force_refresh=False)
|
|
@@ -1420,7 +1432,7 @@ class RecordTools(ToolBase):
|
|
|
1420
1432
|
)
|
|
1421
1433
|
normalized_fields = fields if isinstance(fields, dict) else {}
|
|
1422
1434
|
runtime_lookup = self._candidate_lookup_uses_runtime_scope(
|
|
1423
|
-
record_id=
|
|
1435
|
+
record_id=record_id_int,
|
|
1424
1436
|
workflow_node_id=workflow_node_id,
|
|
1425
1437
|
fields=normalized_fields,
|
|
1426
1438
|
)
|
|
@@ -1431,7 +1443,7 @@ class RecordTools(ToolBase):
|
|
|
1431
1443
|
profile,
|
|
1432
1444
|
context,
|
|
1433
1445
|
app_key=app_key,
|
|
1434
|
-
record_id=
|
|
1446
|
+
record_id=record_id_int,
|
|
1435
1447
|
workflow_node_id=workflow_node_id,
|
|
1436
1448
|
fields=normalized_fields,
|
|
1437
1449
|
)
|
|
@@ -1487,7 +1499,7 @@ class RecordTools(ToolBase):
|
|
|
1487
1499
|
"app_key": app_key,
|
|
1488
1500
|
"field_id": field.que_id,
|
|
1489
1501
|
"field_title": field.que_title,
|
|
1490
|
-
"record_id":
|
|
1502
|
+
"record_id": record_id_text,
|
|
1491
1503
|
"workflow_node_id": workflow_node_id,
|
|
1492
1504
|
"fields_present": bool(normalized_fields),
|
|
1493
1505
|
"keyword": keyword,
|
|
@@ -1753,7 +1765,7 @@ class RecordTools(ToolBase):
|
|
|
1753
1765
|
*,
|
|
1754
1766
|
profile: str,
|
|
1755
1767
|
app_key: str,
|
|
1756
|
-
record_id:
|
|
1768
|
+
record_id: Any,
|
|
1757
1769
|
columns: list[JSONObject | int],
|
|
1758
1770
|
view_id: str | None = None,
|
|
1759
1771
|
workflow_node_id: int | None = None,
|
|
@@ -1761,8 +1773,7 @@ class RecordTools(ToolBase):
|
|
|
1761
1773
|
) -> JSONObject:
|
|
1762
1774
|
"""执行记录相关逻辑。"""
|
|
1763
1775
|
normalized_output_profile = self._normalize_public_output_profile(output_profile, allow_normalized=True)
|
|
1764
|
-
|
|
1765
|
-
raise_tool_error(QingflowApiError.config_error("record_id must be positive"))
|
|
1776
|
+
record_id_int = normalize_positive_id_int(record_id, field_name="record_id")
|
|
1766
1777
|
normalized_columns = _normalize_public_column_selectors(columns)
|
|
1767
1778
|
|
|
1768
1779
|
def runner(session_profile, context):
|
|
@@ -1791,7 +1802,7 @@ class RecordTools(ToolBase):
|
|
|
1791
1802
|
result = self.backend.request(
|
|
1792
1803
|
"GET",
|
|
1793
1804
|
context,
|
|
1794
|
-
f"/view/{resolved_view.view_selection.view_key}/apply/{
|
|
1805
|
+
f"/view/{resolved_view.view_selection.view_key}/apply/{record_id_int}",
|
|
1795
1806
|
)
|
|
1796
1807
|
used_list_type = None
|
|
1797
1808
|
else:
|
|
@@ -1808,7 +1819,7 @@ class RecordTools(ToolBase):
|
|
|
1808
1819
|
result = self.backend.request(
|
|
1809
1820
|
"GET",
|
|
1810
1821
|
context,
|
|
1811
|
-
f"/app/{app_key}/apply/{
|
|
1822
|
+
f"/app/{app_key}/apply/{record_id_int}",
|
|
1812
1823
|
params={"role": 1, "listType": lt},
|
|
1813
1824
|
)
|
|
1814
1825
|
used_list_type = lt
|
|
@@ -1823,7 +1834,7 @@ class RecordTools(ToolBase):
|
|
|
1823
1834
|
raise last_error
|
|
1824
1835
|
raise_tool_error(QingflowApiError.config_error("record_get failed: no accessible listType"))
|
|
1825
1836
|
answer_list = result.get("answers") if isinstance(result, dict) and isinstance(result.get("answers"), list) else []
|
|
1826
|
-
row = _build_flat_row(cast(list[JSONValue], answer_list), selected_fields, apply_id=
|
|
1837
|
+
row = _build_flat_row(cast(list[JSONValue], answer_list), selected_fields, apply_id=record_id_int)
|
|
1827
1838
|
normalized_record, normalized_ambiguous_fields = _build_normalized_row_from_answers(
|
|
1828
1839
|
cast(list[JSONValue], answer_list),
|
|
1829
1840
|
selected_fields,
|
|
@@ -1851,7 +1862,7 @@ class RecordTools(ToolBase):
|
|
|
1851
1862
|
if normalized_columns
|
|
1852
1863
|
else list(index.by_id.values())
|
|
1853
1864
|
)
|
|
1854
|
-
row = _build_flat_row(cast(list[JSONValue], answer_list), selected_fields, apply_id=
|
|
1865
|
+
row = _build_flat_row(cast(list[JSONValue], answer_list), selected_fields, apply_id=record_id_int)
|
|
1855
1866
|
normalized_record, normalized_ambiguous_fields = _build_normalized_row_from_answers(
|
|
1856
1867
|
cast(list[JSONValue], answer_list),
|
|
1857
1868
|
selected_fields,
|
|
@@ -1874,7 +1885,7 @@ class RecordTools(ToolBase):
|
|
|
1874
1885
|
"output_profile": normalized_output_profile,
|
|
1875
1886
|
"data": {
|
|
1876
1887
|
"app_key": app_key,
|
|
1877
|
-
"record_id": _public_record_id_text(
|
|
1888
|
+
"record_id": _public_record_id_text(record_id_int),
|
|
1878
1889
|
"record": row,
|
|
1879
1890
|
"selection": {
|
|
1880
1891
|
"columns": [_column_selector_payload(field_id) for field_id in normalized_columns] if normalized_columns else [],
|
|
@@ -1975,7 +1986,7 @@ class RecordTools(ToolBase):
|
|
|
1975
1986
|
*,
|
|
1976
1987
|
profile: str = DEFAULT_PROFILE,
|
|
1977
1988
|
app_key: str,
|
|
1978
|
-
record_id:
|
|
1989
|
+
record_id: Any | None,
|
|
1979
1990
|
fields: JSONObject | None = None,
|
|
1980
1991
|
items: list[JSONObject] | None = None,
|
|
1981
1992
|
dry_run: bool = False,
|
|
@@ -2004,14 +2015,15 @@ class RecordTools(ToolBase):
|
|
|
2004
2015
|
)
|
|
2005
2016
|
if dry_run:
|
|
2006
2017
|
raise_tool_error(QingflowApiError.config_error("dry_run currently requires items"))
|
|
2007
|
-
if record_id is None
|
|
2018
|
+
if record_id is None:
|
|
2008
2019
|
raise_tool_error(QingflowApiError.config_error("record_id is required"))
|
|
2020
|
+
record_id_int = normalize_positive_id_int(record_id, field_name="record_id")
|
|
2009
2021
|
if fields is not None and not isinstance(fields, dict):
|
|
2010
2022
|
raise_tool_error(QingflowApiError.config_error("fields must be an object map keyed by field title"))
|
|
2011
2023
|
return self._record_update_public_single(
|
|
2012
2024
|
profile=profile,
|
|
2013
2025
|
app_key=app_key,
|
|
2014
|
-
record_id=
|
|
2026
|
+
record_id=record_id_int,
|
|
2015
2027
|
fields=cast(JSONObject, fields or {}),
|
|
2016
2028
|
verify_write=verify_write,
|
|
2017
2029
|
output_profile=normalized_output_profile,
|
|
@@ -2201,7 +2213,7 @@ class RecordTools(ToolBase):
|
|
|
2201
2213
|
def _normalize_public_record_update_batch_items(
|
|
2202
2214
|
self,
|
|
2203
2215
|
*,
|
|
2204
|
-
record_id:
|
|
2216
|
+
record_id: Any | None,
|
|
2205
2217
|
fields: JSONObject | None,
|
|
2206
2218
|
items: list[JSONObject] | None,
|
|
2207
2219
|
) -> list[JSONObject]:
|
|
@@ -2217,9 +2229,10 @@ class RecordTools(ToolBase):
|
|
|
2217
2229
|
for index, item in enumerate(items):
|
|
2218
2230
|
if not isinstance(item, dict):
|
|
2219
2231
|
raise_tool_error(QingflowApiError.config_error(f"items[{index}] must be an object"))
|
|
2220
|
-
normalized_record_id =
|
|
2221
|
-
|
|
2222
|
-
|
|
2232
|
+
normalized_record_id = normalize_positive_id_int(
|
|
2233
|
+
item.get("record_id"),
|
|
2234
|
+
field_name=f"items[{index}].record_id",
|
|
2235
|
+
)
|
|
2223
2236
|
if normalized_record_id in seen_record_ids:
|
|
2224
2237
|
raise_tool_error(
|
|
2225
2238
|
QingflowApiError.config_error(f"duplicate record_id in items: {normalized_record_id}")
|
|
@@ -3069,22 +3082,26 @@ class RecordTools(ToolBase):
|
|
|
3069
3082
|
*,
|
|
3070
3083
|
profile: str = DEFAULT_PROFILE,
|
|
3071
3084
|
app_key: str,
|
|
3072
|
-
record_id:
|
|
3073
|
-
record_ids: list[
|
|
3085
|
+
record_id: Any | None = None,
|
|
3086
|
+
record_ids: list[Any] | None = None,
|
|
3074
3087
|
output_profile: str = "normal",
|
|
3075
3088
|
) -> JSONObject:
|
|
3076
3089
|
"""执行记录相关逻辑。"""
|
|
3077
3090
|
normalized_output_profile = self._normalize_public_output_profile(output_profile)
|
|
3078
3091
|
if not app_key:
|
|
3079
3092
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
3080
|
-
normalized_record_ids
|
|
3081
|
-
|
|
3093
|
+
normalized_record_ids: list[int] = []
|
|
3094
|
+
for index, item in enumerate(record_ids or []):
|
|
3095
|
+
normalized_record_ids.append(normalize_positive_id_int(item, field_name=f"record_ids[{index}]"))
|
|
3096
|
+
delete_ids = normalized_record_ids
|
|
3097
|
+
if not delete_ids and record_id is not None:
|
|
3098
|
+
delete_ids = [normalize_positive_id_int(record_id, field_name="record_id")]
|
|
3082
3099
|
if not delete_ids:
|
|
3083
3100
|
raise_tool_error(QingflowApiError.config_error("record_id or record_ids is required"))
|
|
3084
3101
|
normalized_payload = {
|
|
3085
3102
|
"operation": "delete",
|
|
3086
|
-
"record_id": record_id,
|
|
3087
|
-
"record_ids": delete_ids,
|
|
3103
|
+
"record_id": stringify_backend_id(record_id) if record_id is not None else None,
|
|
3104
|
+
"record_ids": [stringify_backend_id(item) for item in delete_ids],
|
|
3088
3105
|
"answers": [],
|
|
3089
3106
|
"submit_type": 1,
|
|
3090
3107
|
}
|
|
@@ -8527,8 +8544,8 @@ class RecordTools(ToolBase):
|
|
|
8527
8544
|
"""执行内部辅助逻辑。"""
|
|
8528
8545
|
payload: JSONObject = {
|
|
8529
8546
|
"operation": operation,
|
|
8530
|
-
"record_id": record_id,
|
|
8531
|
-
"record_ids": record_ids,
|
|
8547
|
+
"record_id": stringify_backend_id(record_id) if record_id is not None else None,
|
|
8548
|
+
"record_ids": [stringify_backend_id(item) for item in record_ids],
|
|
8532
8549
|
"answers": normalized_answers,
|
|
8533
8550
|
"submit_type": submit_type,
|
|
8534
8551
|
}
|
|
@@ -8727,7 +8744,7 @@ class RecordTools(ToolBase):
|
|
|
8727
8744
|
"output_profile": output_profile,
|
|
8728
8745
|
"data": {
|
|
8729
8746
|
"action": {"operation": operation, "executed": True},
|
|
8730
|
-
"resource": raw_apply.get("resource"),
|
|
8747
|
+
"resource": _public_record_resource(raw_apply.get("resource")),
|
|
8731
8748
|
"verification": raw_apply.get("verification"),
|
|
8732
8749
|
"normalized_payload": normalized_payload,
|
|
8733
8750
|
"blockers": [],
|
|
@@ -10072,8 +10089,9 @@ class RecordTools(ToolBase):
|
|
|
10072
10089
|
"""执行内部辅助逻辑。"""
|
|
10073
10090
|
if not app_key:
|
|
10074
10091
|
raise_tool_error(QingflowApiError.config_error("app_key is required"))
|
|
10075
|
-
|
|
10076
|
-
|
|
10092
|
+
try:
|
|
10093
|
+
normalized_apply_id = normalize_positive_id_int(apply_id, field_name="apply_id")
|
|
10094
|
+
except QingflowApiError:
|
|
10077
10095
|
raise_tool_error(QingflowApiError.config_error("apply_id must be positive"))
|
|
10078
10096
|
return normalized_apply_id
|
|
10079
10097
|
|
|
@@ -11084,10 +11102,14 @@ def _build_flat_row(answer_list: list[JSONValue], fields: list[FormField], *, ap
|
|
|
11084
11102
|
return row
|
|
11085
11103
|
|
|
11086
11104
|
|
|
11087
|
-
def _public_record_id_text(record_id:
|
|
11088
|
-
if record_id is None or record_id
|
|
11105
|
+
def _public_record_id_text(record_id: Any) -> str | None:
|
|
11106
|
+
if record_id is None or isinstance(record_id, bool):
|
|
11089
11107
|
return None
|
|
11090
|
-
|
|
11108
|
+
if isinstance(record_id, int) and record_id <= 0:
|
|
11109
|
+
return None
|
|
11110
|
+
if isinstance(record_id, str) and (not record_id.strip() or not record_id.strip().isdecimal()):
|
|
11111
|
+
return None
|
|
11112
|
+
return stringify_backend_id(record_id)
|
|
11091
11113
|
|
|
11092
11114
|
|
|
11093
11115
|
def _normalize_public_record_rows(rows: list[JSONValue]) -> list[JSONObject]:
|
|
@@ -11640,10 +11662,29 @@ def _field_mapping_entry(role: str, field: FormField | None, *, requested: str)
|
|
|
11640
11662
|
}
|
|
11641
11663
|
|
|
11642
11664
|
|
|
11643
|
-
def _record_resource_payload(record_id:
|
|
11644
|
-
|
|
11665
|
+
def _record_resource_payload(record_id: Any) -> JSONObject | None:
|
|
11666
|
+
public_record_id = _public_record_id_text(record_id)
|
|
11667
|
+
if public_record_id is None:
|
|
11645
11668
|
return None
|
|
11646
|
-
return {"type": "record", "record_id":
|
|
11669
|
+
return {"type": "record", "record_id": public_record_id, "apply_id": public_record_id}
|
|
11670
|
+
|
|
11671
|
+
|
|
11672
|
+
def _public_record_resource(resource: Any) -> Any:
|
|
11673
|
+
if not isinstance(resource, dict) or resource.get("type") != "record":
|
|
11674
|
+
return resource
|
|
11675
|
+
payload = dict(resource)
|
|
11676
|
+
if "record_id" in payload:
|
|
11677
|
+
payload["record_id"] = _public_record_id_text(payload.get("record_id"))
|
|
11678
|
+
if "apply_id" in payload:
|
|
11679
|
+
payload["apply_id"] = _public_record_id_text(payload.get("apply_id"))
|
|
11680
|
+
record_ids = payload.get("record_ids")
|
|
11681
|
+
if isinstance(record_ids, list):
|
|
11682
|
+
payload["record_ids"] = [
|
|
11683
|
+
stringify_backend_id(item)
|
|
11684
|
+
for item in record_ids
|
|
11685
|
+
if stringify_backend_id(item) is not None
|
|
11686
|
+
]
|
|
11687
|
+
return payload
|
|
11647
11688
|
|
|
11648
11689
|
|
|
11649
11690
|
def _query_id() -> str:
|