@qingflow-tech/qingflow-app-user-mcp 1.0.7 → 1.0.9
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/package.json +1 -1
- package/pyproject.toml +1 -1
- package/skills/qingflow-app-user/references/public-surface-sync.md +3 -0
- package/src/qingflow_mcp/builder_facade/models.py +205 -11
- package/src/qingflow_mcp/builder_facade/service.py +2303 -159
- package/src/qingflow_mcp/cli/commands/builder.py +8 -0
- package/src/qingflow_mcp/cli/commands/record.py +55 -1
- package/src/qingflow_mcp/public_surface.py +2 -2
- package/src/qingflow_mcp/response_trim.py +14 -0
- package/src/qingflow_mcp/server.py +1 -0
- package/src/qingflow_mcp/server_app_builder.py +13 -2
- package/src/qingflow_mcp/server_app_user.py +1 -0
- package/src/qingflow_mcp/tools/ai_builder_tools.py +199 -10
|
@@ -43,6 +43,7 @@ from ..builder_facade.models import (
|
|
|
43
43
|
SchemaPlanRequest,
|
|
44
44
|
VisibilityPatch,
|
|
45
45
|
ViewFilterOperator,
|
|
46
|
+
ViewPartialPatch,
|
|
46
47
|
ViewUpsertPatch,
|
|
47
48
|
ViewsPreset,
|
|
48
49
|
ViewsPlanRequest,
|
|
@@ -60,6 +61,14 @@ from .solution_tools import SolutionTools
|
|
|
60
61
|
from .view_tools import ViewTools
|
|
61
62
|
from .workflow_tools import WorkflowTools
|
|
62
63
|
|
|
64
|
+
|
|
65
|
+
def _normalize_builder_view_key(value: str) -> str:
|
|
66
|
+
raw = str(value or "").strip()
|
|
67
|
+
if raw.startswith("custom:"):
|
|
68
|
+
return raw.split(":", 1)[1].strip()
|
|
69
|
+
return raw
|
|
70
|
+
|
|
71
|
+
|
|
63
72
|
PUBLIC_STABLE_FLOW_NODE_TYPES = ["start", "approve", "fill", "copy", "webhook", "end"]
|
|
64
73
|
|
|
65
74
|
|
|
@@ -227,6 +236,7 @@ class AiBuilderTools(ToolBase):
|
|
|
227
236
|
profile: str = DEFAULT_PROFILE,
|
|
228
237
|
app_key: str = "",
|
|
229
238
|
upsert_buttons: list[JSONObject] | None = None,
|
|
239
|
+
patch_buttons: list[JSONObject] | None = None,
|
|
230
240
|
remove_buttons: list[JSONObject] | None = None,
|
|
231
241
|
view_configs: list[JSONObject] | None = None,
|
|
232
242
|
) -> JSONObject:
|
|
@@ -234,6 +244,7 @@ class AiBuilderTools(ToolBase):
|
|
|
234
244
|
profile=profile,
|
|
235
245
|
app_key=app_key,
|
|
236
246
|
upsert_buttons=upsert_buttons or [],
|
|
247
|
+
patch_buttons=patch_buttons or [],
|
|
237
248
|
remove_buttons=remove_buttons or [],
|
|
238
249
|
view_configs=view_configs or [],
|
|
239
250
|
)
|
|
@@ -243,6 +254,7 @@ class AiBuilderTools(ToolBase):
|
|
|
243
254
|
profile: str = DEFAULT_PROFILE,
|
|
244
255
|
app_key: str = "",
|
|
245
256
|
upsert_resources: list[JSONObject] | None = None,
|
|
257
|
+
patch_resources: list[JSONObject] | None = None,
|
|
246
258
|
remove_associated_item_ids: list[int] | None = None,
|
|
247
259
|
reorder_associated_item_ids: list[int] | None = None,
|
|
248
260
|
view_configs: list[JSONObject] | None = None,
|
|
@@ -251,6 +263,7 @@ class AiBuilderTools(ToolBase):
|
|
|
251
263
|
profile=profile,
|
|
252
264
|
app_key=app_key,
|
|
253
265
|
upsert_resources=upsert_resources or [],
|
|
266
|
+
patch_resources=patch_resources or [],
|
|
254
267
|
remove_associated_item_ids=remove_associated_item_ids or [],
|
|
255
268
|
reorder_associated_item_ids=reorder_associated_item_ids or [],
|
|
256
269
|
view_configs=view_configs or [],
|
|
@@ -395,6 +408,7 @@ class AiBuilderTools(ToolBase):
|
|
|
395
408
|
app_key: str = "",
|
|
396
409
|
publish: bool = True,
|
|
397
410
|
upsert_views: list[JSONObject] | None = None,
|
|
411
|
+
patch_views: list[JSONObject] | None = None,
|
|
398
412
|
remove_views: list[str] | None = None,
|
|
399
413
|
) -> JSONObject:
|
|
400
414
|
return self.app_views_apply(
|
|
@@ -402,6 +416,7 @@ class AiBuilderTools(ToolBase):
|
|
|
402
416
|
app_key=app_key,
|
|
403
417
|
publish=publish,
|
|
404
418
|
upsert_views=upsert_views or [],
|
|
419
|
+
patch_views=patch_views or [],
|
|
405
420
|
remove_views=remove_views or [],
|
|
406
421
|
)
|
|
407
422
|
|
|
@@ -410,6 +425,7 @@ class AiBuilderTools(ToolBase):
|
|
|
410
425
|
profile: str = DEFAULT_PROFILE,
|
|
411
426
|
app_key: str = "",
|
|
412
427
|
upsert_charts: list[JSONObject] | None = None,
|
|
428
|
+
patch_charts: list[JSONObject] | None = None,
|
|
413
429
|
remove_chart_ids: list[str] | None = None,
|
|
414
430
|
reorder_chart_ids: list[str] | None = None,
|
|
415
431
|
) -> JSONObject:
|
|
@@ -417,6 +433,7 @@ class AiBuilderTools(ToolBase):
|
|
|
417
433
|
profile=profile,
|
|
418
434
|
app_key=app_key,
|
|
419
435
|
upsert_charts=upsert_charts or [],
|
|
436
|
+
patch_charts=patch_charts or [],
|
|
420
437
|
remove_chart_ids=remove_chart_ids or [],
|
|
421
438
|
reorder_chart_ids=reorder_chart_ids or [],
|
|
422
439
|
)
|
|
@@ -882,6 +899,7 @@ class AiBuilderTools(ToolBase):
|
|
|
882
899
|
profile: str,
|
|
883
900
|
app_key: str,
|
|
884
901
|
upsert_buttons: list[JSONObject],
|
|
902
|
+
patch_buttons: list[JSONObject] | None = None,
|
|
885
903
|
remove_buttons: list[JSONObject],
|
|
886
904
|
view_configs: list[JSONObject] | None = None,
|
|
887
905
|
) -> JSONObject:
|
|
@@ -889,6 +907,7 @@ class AiBuilderTools(ToolBase):
|
|
|
889
907
|
raw_request = {
|
|
890
908
|
"app_key": app_key,
|
|
891
909
|
"upsert_buttons": upsert_buttons,
|
|
910
|
+
"patch_buttons": patch_buttons or [],
|
|
892
911
|
"remove_buttons": remove_buttons,
|
|
893
912
|
"view_configs": view_configs or [],
|
|
894
913
|
}
|
|
@@ -936,11 +955,13 @@ class AiBuilderTools(ToolBase):
|
|
|
936
955
|
remove_associated_item_ids: list[int],
|
|
937
956
|
reorder_associated_item_ids: list[int],
|
|
938
957
|
view_configs: list[JSONObject],
|
|
958
|
+
patch_resources: list[JSONObject] | None = None,
|
|
939
959
|
) -> JSONObject:
|
|
940
960
|
"""执行应用关联资源 apply 逻辑。"""
|
|
941
961
|
raw_request = {
|
|
942
962
|
"app_key": app_key,
|
|
943
963
|
"upsert_resources": upsert_resources,
|
|
964
|
+
"patch_resources": patch_resources or [],
|
|
944
965
|
"remove_associated_item_ids": remove_associated_item_ids,
|
|
945
966
|
"reorder_associated_item_ids": reorder_associated_item_ids,
|
|
946
967
|
"view_configs": view_configs,
|
|
@@ -1272,7 +1293,7 @@ class AiBuilderTools(ToolBase):
|
|
|
1272
1293
|
@tool_cn_name("视图详情查询")
|
|
1273
1294
|
def view_get(self, *, profile: str, view_key: str = "", viewgraph_key: str = "") -> JSONObject:
|
|
1274
1295
|
"""执行视图相关逻辑。"""
|
|
1275
|
-
resolved_view_key = str(view_key or viewgraph_key or "").strip()
|
|
1296
|
+
resolved_view_key = _normalize_builder_view_key(str(view_key or viewgraph_key or "").strip())
|
|
1276
1297
|
normalized_args = {"view_key": resolved_view_key}
|
|
1277
1298
|
return _safe_tool_call(
|
|
1278
1299
|
lambda: self._facade.view_get(profile=profile, view_key=resolved_view_key),
|
|
@@ -1853,6 +1874,7 @@ class AiBuilderTools(ToolBase):
|
|
|
1853
1874
|
app_key: str,
|
|
1854
1875
|
publish: bool = True,
|
|
1855
1876
|
upsert_views: list[JSONObject],
|
|
1877
|
+
patch_views: list[JSONObject] | None = None,
|
|
1856
1878
|
remove_views: list[str],
|
|
1857
1879
|
) -> JSONObject:
|
|
1858
1880
|
"""执行应用相关逻辑。"""
|
|
@@ -1861,6 +1883,7 @@ class AiBuilderTools(ToolBase):
|
|
|
1861
1883
|
app_key=app_key,
|
|
1862
1884
|
publish=publish,
|
|
1863
1885
|
upsert_views=upsert_views,
|
|
1886
|
+
patch_views=patch_views or [],
|
|
1864
1887
|
remove_views=remove_views,
|
|
1865
1888
|
)
|
|
1866
1889
|
return self._retry_after_self_lock_release(
|
|
@@ -1872,6 +1895,7 @@ class AiBuilderTools(ToolBase):
|
|
|
1872
1895
|
publish=publish,
|
|
1873
1896
|
remove_views=remove_views,
|
|
1874
1897
|
upsert_views=upsert_views,
|
|
1898
|
+
patch_views=patch_views or [],
|
|
1875
1899
|
),
|
|
1876
1900
|
)
|
|
1877
1901
|
|
|
@@ -1882,9 +1906,53 @@ class AiBuilderTools(ToolBase):
|
|
|
1882
1906
|
app_key: str,
|
|
1883
1907
|
publish: bool = True,
|
|
1884
1908
|
upsert_views: list[JSONObject],
|
|
1909
|
+
patch_views: list[JSONObject],
|
|
1885
1910
|
remove_views: list[str],
|
|
1886
1911
|
) -> JSONObject:
|
|
1887
1912
|
"""执行内部辅助逻辑。"""
|
|
1913
|
+
if patch_views:
|
|
1914
|
+
try:
|
|
1915
|
+
parsed_views = [ViewUpsertPatch.model_validate(item) for item in (upsert_views or [])]
|
|
1916
|
+
parsed_patch_views = [ViewPartialPatch.model_validate(item) for item in patch_views]
|
|
1917
|
+
except ValidationError as exc:
|
|
1918
|
+
return _visibility_validation_failure(
|
|
1919
|
+
str(exc),
|
|
1920
|
+
tool_name="app_views_apply",
|
|
1921
|
+
exc=exc,
|
|
1922
|
+
suggested_next_call={
|
|
1923
|
+
"tool_name": "app_views_apply",
|
|
1924
|
+
"arguments": {
|
|
1925
|
+
"profile": profile,
|
|
1926
|
+
"app_key": app_key,
|
|
1927
|
+
"publish": publish,
|
|
1928
|
+
"upsert_views": upsert_views or [],
|
|
1929
|
+
"patch_views": [
|
|
1930
|
+
{"view_key": "VIEW_KEY", "set": {"query_conditions": {"enabled": True, "rows": [["字段A"]]}}},
|
|
1931
|
+
],
|
|
1932
|
+
"remove_views": remove_views or [],
|
|
1933
|
+
},
|
|
1934
|
+
},
|
|
1935
|
+
)
|
|
1936
|
+
normalized_args = {
|
|
1937
|
+
"app_key": app_key,
|
|
1938
|
+
"publish": publish,
|
|
1939
|
+
"upsert_views": [view.model_dump(mode="json") for view in parsed_views],
|
|
1940
|
+
"patch_views": [patch.model_dump(mode="json") for patch in parsed_patch_views],
|
|
1941
|
+
"remove_views": list(remove_views or []),
|
|
1942
|
+
}
|
|
1943
|
+
return _safe_tool_call(
|
|
1944
|
+
lambda: self._facade.app_views_apply(
|
|
1945
|
+
profile=profile,
|
|
1946
|
+
app_key=app_key,
|
|
1947
|
+
publish=publish,
|
|
1948
|
+
upsert_views=parsed_views,
|
|
1949
|
+
patch_views=parsed_patch_views,
|
|
1950
|
+
remove_views=list(remove_views or []),
|
|
1951
|
+
),
|
|
1952
|
+
error_code="VIEWS_APPLY_FAILED",
|
|
1953
|
+
normalized_args=normalized_args,
|
|
1954
|
+
suggested_next_call={"tool_name": "app_views_apply", "arguments": {"profile": profile, **normalized_args}},
|
|
1955
|
+
)
|
|
1888
1956
|
plan_result = self._rewrite_plan_result_for_apply(
|
|
1889
1957
|
result=self.app_views_plan(
|
|
1890
1958
|
profile=profile,
|
|
@@ -1933,6 +2001,7 @@ class AiBuilderTools(ToolBase):
|
|
|
1933
2001
|
app_key=str(plan_args.get("app_key") or app_key),
|
|
1934
2002
|
publish=publish,
|
|
1935
2003
|
upsert_views=parsed_views,
|
|
2004
|
+
patch_views=[],
|
|
1936
2005
|
remove_views=list(plan_args.get("remove_views") or remove_views),
|
|
1937
2006
|
),
|
|
1938
2007
|
error_code="VIEWS_APPLY_FAILED",
|
|
@@ -1947,6 +2016,7 @@ class AiBuilderTools(ToolBase):
|
|
|
1947
2016
|
profile: str,
|
|
1948
2017
|
app_key: str,
|
|
1949
2018
|
upsert_charts: list[JSONObject],
|
|
2019
|
+
patch_charts: list[JSONObject] | None = None,
|
|
1950
2020
|
remove_chart_ids: list[str],
|
|
1951
2021
|
reorder_chart_ids: list[str],
|
|
1952
2022
|
) -> JSONObject:
|
|
@@ -1955,6 +2025,7 @@ class AiBuilderTools(ToolBase):
|
|
|
1955
2025
|
profile=profile,
|
|
1956
2026
|
app_key=app_key,
|
|
1957
2027
|
upsert_charts=upsert_charts,
|
|
2028
|
+
patch_charts=patch_charts or [],
|
|
1958
2029
|
remove_chart_ids=remove_chart_ids,
|
|
1959
2030
|
reorder_chart_ids=reorder_chart_ids,
|
|
1960
2031
|
)
|
|
@@ -1968,6 +2039,7 @@ class AiBuilderTools(ToolBase):
|
|
|
1968
2039
|
upsert_charts: list[JSONObject],
|
|
1969
2040
|
remove_chart_ids: list[str],
|
|
1970
2041
|
reorder_chart_ids: list[str],
|
|
2042
|
+
patch_charts: list[JSONObject] | None = None,
|
|
1971
2043
|
) -> JSONObject:
|
|
1972
2044
|
"""执行应用相关逻辑。"""
|
|
1973
2045
|
try:
|
|
@@ -1975,6 +2047,7 @@ class AiBuilderTools(ToolBase):
|
|
|
1975
2047
|
{
|
|
1976
2048
|
"app_key": app_key,
|
|
1977
2049
|
"upsert_charts": upsert_charts or [],
|
|
2050
|
+
"patch_charts": patch_charts or [],
|
|
1978
2051
|
"remove_chart_ids": remove_chart_ids or [],
|
|
1979
2052
|
"reorder_chart_ids": reorder_chart_ids or [],
|
|
1980
2053
|
}
|
|
@@ -2550,6 +2623,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
2550
2623
|
"allowed_values": deepcopy(_VISIBILITY_ALLOWED_VALUES),
|
|
2551
2624
|
"execution_notes": [
|
|
2552
2625
|
"create or update package metadata, visibility, grouping, and ordering in one call",
|
|
2626
|
+
"metadata keys omitted on update are preserved",
|
|
2553
2627
|
"package_id maps internally to backend tagId; do not use tag_id in public calls",
|
|
2554
2628
|
"items is a full package layout tree; omitting existing app/portal items is blocked unless allow_detach=true",
|
|
2555
2629
|
"item shapes: {type:'app', app_key}, {type:'portal', dash_key}, or {type:'group', group_id?, name, items:[...]}",
|
|
@@ -2696,6 +2770,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
2696
2770
|
"allowed_keys": [
|
|
2697
2771
|
"app_key",
|
|
2698
2772
|
"upsert_buttons",
|
|
2773
|
+
"patch_buttons",
|
|
2699
2774
|
"remove_buttons",
|
|
2700
2775
|
"view_configs",
|
|
2701
2776
|
"upsert_buttons[].client_key",
|
|
@@ -2713,6 +2788,10 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
2713
2788
|
"upsert_buttons[].trigger_add_data_config.field_mappings[].source_field",
|
|
2714
2789
|
"upsert_buttons[].trigger_add_data_config.field_mappings[].target_field",
|
|
2715
2790
|
"upsert_buttons[].trigger_add_data_config.default_values",
|
|
2791
|
+
"patch_buttons[].button_id",
|
|
2792
|
+
"patch_buttons[].button_text",
|
|
2793
|
+
"patch_buttons[].set",
|
|
2794
|
+
"patch_buttons[].unset",
|
|
2716
2795
|
"view_configs[].view_key",
|
|
2717
2796
|
"view_configs[].mode",
|
|
2718
2797
|
"view_configs[].buttons",
|
|
@@ -2728,6 +2807,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
2728
2807
|
],
|
|
2729
2808
|
"aliases": {
|
|
2730
2809
|
"upsertButtons": "upsert_buttons",
|
|
2810
|
+
"patchButtons": "patch_buttons",
|
|
2731
2811
|
"removeButtons": "remove_buttons",
|
|
2732
2812
|
"viewConfigs": "view_configs",
|
|
2733
2813
|
"clientKey": "client_key",
|
|
@@ -2767,15 +2847,19 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
2767
2847
|
},
|
|
2768
2848
|
"execution_notes": [
|
|
2769
2849
|
"this is the default custom-button write path; old list/get/create/update/delete tools are hidden from the public agent surface",
|
|
2850
|
+
"use patch_buttons for partial parameter replacement on existing buttons; the tool reads current button detail, merges patch_buttons[].set/unset, then submits the backend full-save payload internally",
|
|
2770
2851
|
"button_id targets an existing button; without button_id, button_text is used as an exact unique upsert key, otherwise a new button is created",
|
|
2771
2852
|
"for addData buttons, use trigger_add_data_config.target_app_key plus field_mappings/default_values; field_mappings compiles to backend queRelation",
|
|
2853
|
+
"field_mappings.source_field accepts source schema fields and supported system fields: 数据ID/row_record_id/apply_id/_id maps to current record id (-17), 编号/record_number maps to visible record number (0)",
|
|
2854
|
+
"to fill a target relation field with the current source record, map source_field='数据ID' to the target relation field; default_values is for static constants, not dynamic current-record values",
|
|
2772
2855
|
"do not write raw que_relation unless maintaining a legacy config; field_mappings/default_values and que_relation are mutually exclusive",
|
|
2773
2856
|
"view_configs binds custom buttons into views in the same apply call; button_ref may be a same-call client_key, a button_id, or an exact unique existing button_text",
|
|
2857
|
+
"view_configs[].view_key is the raw builder view key from app_get.views[].view_key; do not pass record-data view_id values like custom:VIEW_KEY",
|
|
2774
2858
|
"view_configs[].buttons is required in merge mode; omitting buttons is blocked to avoid no-op writes and accidental publish",
|
|
2775
2859
|
"view_configs[].mode defaults to merge; use mode=replace or an explicit empty buttons list to replace/clear a view's custom button bindings",
|
|
2776
2860
|
"advanced view button binding supports button_limit, button_formula, button_formula_type, and print_tpls when visibility or print-template behavior is required",
|
|
2777
2861
|
"default placements are header and detail; header maps to frontend top buttons",
|
|
2778
|
-
"placement=list
|
|
2862
|
+
"placement=list configures backend INSIDE row/list buttons; header maps to TOP and detail maps to DETAIL",
|
|
2779
2863
|
"remove_buttons supports button_id or exact unique button_text",
|
|
2780
2864
|
"all operations share one edit context and publish after at least one write succeeds; there is no draft-only mode for this tool",
|
|
2781
2865
|
"background_color and text_color cannot both be white",
|
|
@@ -2792,6 +2876,12 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
2792
2876
|
"trigger_link_url": "https://example.com",
|
|
2793
2877
|
}
|
|
2794
2878
|
],
|
|
2879
|
+
"patch_buttons": [
|
|
2880
|
+
{
|
|
2881
|
+
"button_text": "同步客户",
|
|
2882
|
+
"set": {"trigger_link_url": "https://example.com/new"},
|
|
2883
|
+
}
|
|
2884
|
+
],
|
|
2795
2885
|
"remove_buttons": [{"button_text": "旧按钮"}],
|
|
2796
2886
|
"view_configs": [],
|
|
2797
2887
|
},
|
|
@@ -2820,11 +2910,36 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
2820
2910
|
}
|
|
2821
2911
|
],
|
|
2822
2912
|
},
|
|
2913
|
+
"relation_current_record_example": {
|
|
2914
|
+
"profile": "default",
|
|
2915
|
+
"app_key": "EMPLOYEE_APP",
|
|
2916
|
+
"upsert_buttons": [
|
|
2917
|
+
{
|
|
2918
|
+
"client_key": "add_worklog",
|
|
2919
|
+
"button_text": "快捷添加工时",
|
|
2920
|
+
"style_preset": "neutral_outline",
|
|
2921
|
+
"button_icon": "ex-plus-circle",
|
|
2922
|
+
"trigger_action": "addData",
|
|
2923
|
+
"trigger_add_data_config": {
|
|
2924
|
+
"target_app_key": "WORKLOG_APP",
|
|
2925
|
+
"field_mappings": [{"source_field": "数据ID", "target_field": "关联员工"}],
|
|
2926
|
+
"default_values": {"状态": "待提交"},
|
|
2927
|
+
},
|
|
2928
|
+
}
|
|
2929
|
+
],
|
|
2930
|
+
"view_configs": [
|
|
2931
|
+
{
|
|
2932
|
+
"view_key": "RAW_VIEW_KEY",
|
|
2933
|
+
"buttons": [{"button_ref": "add_worklog", "placement": "detail", "primary": True}],
|
|
2934
|
+
}
|
|
2935
|
+
],
|
|
2936
|
+
},
|
|
2823
2937
|
},
|
|
2824
2938
|
"app_associated_resources_apply": {
|
|
2825
2939
|
"allowed_keys": [
|
|
2826
2940
|
"app_key",
|
|
2827
2941
|
"upsert_resources",
|
|
2942
|
+
"patch_resources",
|
|
2828
2943
|
"remove_associated_item_ids",
|
|
2829
2944
|
"reorder_associated_item_ids",
|
|
2830
2945
|
"view_configs",
|
|
@@ -2835,7 +2950,15 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
2835
2950
|
"upsert_resources[].view_key",
|
|
2836
2951
|
"upsert_resources[].chart_key",
|
|
2837
2952
|
"upsert_resources[].report_source",
|
|
2953
|
+
"upsert_resources[].match_mappings",
|
|
2954
|
+
"upsert_resources[].match_mappings[].target_field",
|
|
2955
|
+
"upsert_resources[].match_mappings[].source_field",
|
|
2956
|
+
"upsert_resources[].match_mappings[].value",
|
|
2957
|
+
"upsert_resources[].match_mappings[].operator",
|
|
2838
2958
|
"upsert_resources[].match_rules",
|
|
2959
|
+
"patch_resources[].associated_item_id",
|
|
2960
|
+
"patch_resources[].set",
|
|
2961
|
+
"patch_resources[].unset",
|
|
2839
2962
|
"view_configs[].view_key",
|
|
2840
2963
|
"view_configs[].visible",
|
|
2841
2964
|
"view_configs[].limit_type",
|
|
@@ -2844,6 +2967,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
2844
2967
|
],
|
|
2845
2968
|
"aliases": {
|
|
2846
2969
|
"upsertResources": "upsert_resources",
|
|
2970
|
+
"patchResources": "patch_resources",
|
|
2847
2971
|
"resources": "upsert_resources",
|
|
2848
2972
|
"removeAssociatedItemIds": "remove_associated_item_ids",
|
|
2849
2973
|
"reorderAssociatedItemIds": "reorder_associated_item_ids",
|
|
@@ -2852,9 +2976,11 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
2852
2976
|
"graphType": "graph_type",
|
|
2853
2977
|
"targetAppKey": "target_app_key",
|
|
2854
2978
|
"chartKey": "chart_key",
|
|
2979
|
+
"chartId": "chart_key",
|
|
2855
2980
|
"viewKey": "view_key",
|
|
2856
2981
|
"viewgraphKey": "view_key",
|
|
2857
2982
|
"reportSource": "report_source",
|
|
2983
|
+
"matchMappings": "match_mappings",
|
|
2858
2984
|
"matchRules": "match_rules",
|
|
2859
2985
|
"associatedItemRefs": "associated_item_refs",
|
|
2860
2986
|
"associatedItemIds": "associated_item_ids",
|
|
@@ -2865,11 +2991,18 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
2865
2991
|
"view_configs[].limit_type": ["all", "select"],
|
|
2866
2992
|
},
|
|
2867
2993
|
"execution_notes": [
|
|
2994
|
+
"this tool manages Qingflow in-app associated report/view display; it does not create or edit QingBI report bodies/configs",
|
|
2995
|
+
"create or edit app-source BI report bodies first with app_charts_apply, then attach the resulting chart_id here with graph_type=chart; dataset BI reports can only be attached when they already exist",
|
|
2868
2996
|
"this is the default associated report/view path; it manages both the app-level associated resource pool and per-view display config",
|
|
2869
|
-
"
|
|
2997
|
+
"use patch_resources for partial parameter replacement on existing associated resources; the tool reads the current resource including backend-required raw fields, merges patch_resources[].set/unset, then submits the backend full-save payload internally",
|
|
2998
|
+
"associated_item_id is form_asos_chart.id from app_get.associated_resources[].associated_item_id; view_configs/remove/reorder may also pass an existing associated resource's chart_id/chart_key/view_key and the tool resolves it to the internal id",
|
|
2999
|
+
"before creating an associated resource, read app_get.associated_resources and reuse an existing item with patch_resources when target_app_key + view_key/chart_key already matches; repeated upsert_resources without associated_item_id can create duplicate associated items",
|
|
2870
3000
|
"graph_type=view uses view_key and internally compiles to the Qingflow view source; graph_type=chart uses chart_key and defaults to report_source=app",
|
|
2871
|
-
"report_source=app maps to BI_QINGFLOW; report_source=dataset maps to BI_DATASET; do not pass raw backend sourceType",
|
|
2872
|
-
"
|
|
3001
|
+
"report_source=app maps to BI_QINGFLOW; report_source=dataset maps to BI_DATASET for associating an existing dataset report; do not pass raw backend sourceType",
|
|
3002
|
+
"use match_mappings for associated view/report filtering; dynamic conditions use source_field and static conditions use value",
|
|
3003
|
+
"match_mappings.source_field accepts source schema fields plus system fields 数据ID(-17) and 编号(0); match_mappings compiles to backend matchRules",
|
|
3004
|
+
"do not write raw match_rules unless preserving a legacy backend config; match_mappings and match_rules are mutually exclusive",
|
|
3005
|
+
"client_key only lets a view_config reference a resource created earlier in the same apply call through associated_item_refs; it is not persisted and cannot deduplicate later apply calls",
|
|
2873
3006
|
"this tool publishes after at least one write succeeds; there is no draft-only mode",
|
|
2874
3007
|
"visible=false hides the associated-resource area without clearing previous selected ids; visible=true with limit_type=all shows the whole app-level pool",
|
|
2875
3008
|
],
|
|
@@ -2882,7 +3015,13 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
2882
3015
|
"graph_type": "view",
|
|
2883
3016
|
"target_app_key": "TARGET_APP",
|
|
2884
3017
|
"view_key": "VIEW_KEY",
|
|
2885
|
-
"
|
|
3018
|
+
"match_mappings": [{"target_field": "关联员工", "source_field": "数据ID"}],
|
|
3019
|
+
}
|
|
3020
|
+
],
|
|
3021
|
+
"patch_resources": [
|
|
3022
|
+
{
|
|
3023
|
+
"associated_item_id": 123,
|
|
3024
|
+
"set": {"match_mappings": [{"target_field": "状态", "value": "待提交"}]},
|
|
2886
3025
|
}
|
|
2887
3026
|
],
|
|
2888
3027
|
"remove_associated_item_ids": [],
|
|
@@ -3009,6 +3148,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3009
3148
|
"create mode: package_id + app_name + create_if_missing=true",
|
|
3010
3149
|
"create mode defaults new app visibility to workspace/not when visibility is omitted; edit mode preserves current visibility when omitted",
|
|
3011
3150
|
*_VISIBILITY_EXECUTION_NOTES,
|
|
3151
|
+
"update_fields is the field-level partial update path; it reads current form schema and preserves untouched field config",
|
|
3012
3152
|
"multiple relation fields are backend-risky; read verification.relation_field_limit_verified and warnings before declaring the schema stable",
|
|
3013
3153
|
"backend 49614 is normalized to MULTIPLE_RELATION_FIELDS_UNSUPPORTED with a workaround message",
|
|
3014
3154
|
"relation_mode=multiple maps to referenceConfig.optionalDataNum=0",
|
|
@@ -3208,6 +3348,8 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3208
3348
|
},
|
|
3209
3349
|
"allowed_values": {"mode": [member.value for member in LayoutApplyMode]},
|
|
3210
3350
|
"execution_notes": [
|
|
3351
|
+
"mode=merge is the layout partial update path: mentioned sections are merged and unmentioned fields are preserved",
|
|
3352
|
+
"mode=replace is full layout replacement and should be used only when intentionally rewriting all sections",
|
|
3211
3353
|
"layout verification is split into layout_verified and layout_summary_verified",
|
|
3212
3354
|
"LAYOUT_SUMMARY_UNVERIFIED means raw form readback is stronger than the compact summary",
|
|
3213
3355
|
],
|
|
@@ -3285,6 +3427,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3285
3427
|
],
|
|
3286
3428
|
"execution_notes": [
|
|
3287
3429
|
"public flow building is intentionally limited to linear workflows",
|
|
3430
|
+
"app_flow_apply is replace-only; do not treat node snippets as partial patches",
|
|
3288
3431
|
"branch and condition nodes are disabled because the backend workflow route is not front-end stable for these node types",
|
|
3289
3432
|
"workflow verification only covers linear node structure in the public tool surface",
|
|
3290
3433
|
],
|
|
@@ -3308,7 +3451,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3308
3451
|
},
|
|
3309
3452
|
},
|
|
3310
3453
|
"app_views_plan": {
|
|
3311
|
-
"allowed_keys": ["app_key", "upsert_views", "remove_views", "preset", "upsert_views[].view_key", "upsert_views[].buttons", "upsert_views[].visibility", "upsert_views[].query_conditions"],
|
|
3454
|
+
"allowed_keys": ["app_key", "upsert_views", "patch_views", "remove_views", "preset", "upsert_views[].view_key", "upsert_views[].buttons", "upsert_views[].visibility", "upsert_views[].query_conditions", "patch_views[].view_key", "patch_views[].name", "patch_views[].set", "patch_views[].unset"],
|
|
3312
3455
|
"aliases": {
|
|
3313
3456
|
"fields": "columns",
|
|
3314
3457
|
"column_names": "columns",
|
|
@@ -3322,6 +3465,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3322
3465
|
"queryConditions": "query_conditions",
|
|
3323
3466
|
"query_condition": "query_conditions",
|
|
3324
3467
|
"queryCondition": "query_conditions",
|
|
3468
|
+
"patchViews": "patch_views",
|
|
3325
3469
|
"startField": "start_field",
|
|
3326
3470
|
"endField": "end_field",
|
|
3327
3471
|
"titleField": "title_field",
|
|
@@ -3346,6 +3490,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3346
3490
|
"upsert_views[].visibility may set per-view visibility; omit it to preserve an existing view's auth or default a new view to workspace/not",
|
|
3347
3491
|
"filters are saved fixed filters that apply when the view opens; query_conditions configure the frontend query panel and only apply after a user enters query values",
|
|
3348
3492
|
"upsert_views[].query_conditions.rows is a layout matrix of field names; it is compiled to backend queryCondition queIds",
|
|
3493
|
+
"use patch_views for partial parameter replacement on existing views; the tool reads current config, merges patch_views[].set/unset, then submits the backend full-save payload internally",
|
|
3349
3494
|
"view associated report/view display is now configured through app_associated_resources_apply, not app_views_apply",
|
|
3350
3495
|
"for multi-value operators such as in, pass values as a list; value may also be used as an alias when it already contains a list",
|
|
3351
3496
|
*_VISIBILITY_EXECUTION_NOTES,
|
|
@@ -3357,6 +3502,22 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3357
3502
|
"remove_views": [],
|
|
3358
3503
|
},
|
|
3359
3504
|
"query_conditions_example": {
|
|
3505
|
+
"profile": "default",
|
|
3506
|
+
"app_key": "APP_KEY",
|
|
3507
|
+
"patch_views": [
|
|
3508
|
+
{
|
|
3509
|
+
"view_key": "VIEW_KEY",
|
|
3510
|
+
"set": {
|
|
3511
|
+
"query_conditions": {
|
|
3512
|
+
"enabled": True,
|
|
3513
|
+
"rows": [["客户名称", "负责人"], ["创建时间"]],
|
|
3514
|
+
}
|
|
3515
|
+
},
|
|
3516
|
+
}
|
|
3517
|
+
],
|
|
3518
|
+
"remove_views": [],
|
|
3519
|
+
},
|
|
3520
|
+
"full_upsert_query_conditions_example": {
|
|
3360
3521
|
"profile": "default",
|
|
3361
3522
|
"app_key": "APP_KEY",
|
|
3362
3523
|
"upsert_views": [
|
|
@@ -3393,7 +3554,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3393
3554
|
},
|
|
3394
3555
|
},
|
|
3395
3556
|
"app_views_apply": {
|
|
3396
|
-
"allowed_keys": ["app_key", "publish", "upsert_views", "remove_views", "upsert_views[].view_key", "upsert_views[].buttons", "upsert_views[].visibility", "upsert_views[].query_conditions"],
|
|
3557
|
+
"allowed_keys": ["app_key", "publish", "upsert_views", "patch_views", "remove_views", "upsert_views[].view_key", "upsert_views[].buttons", "upsert_views[].visibility", "upsert_views[].query_conditions", "patch_views[].view_key", "patch_views[].name", "patch_views[].set", "patch_views[].unset"],
|
|
3397
3558
|
"aliases": {
|
|
3398
3559
|
"fields": "columns",
|
|
3399
3560
|
"column_names": "columns",
|
|
@@ -3407,6 +3568,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3407
3568
|
"queryConditions": "query_conditions",
|
|
3408
3569
|
"query_condition": "query_conditions",
|
|
3409
3570
|
"queryCondition": "query_conditions",
|
|
3571
|
+
"patchViews": "patch_views",
|
|
3410
3572
|
"startField": "start_field",
|
|
3411
3573
|
"endField": "end_field",
|
|
3412
3574
|
"titleField": "title_field",
|
|
@@ -3435,6 +3597,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3435
3597
|
"upsert_views[].visibility may set per-view visibility; omit it to preserve an existing view's auth or default a new view to workspace/not",
|
|
3436
3598
|
"filters are saved fixed filters that apply when the view opens; query_conditions configure the frontend query panel and only apply after a user enters query values",
|
|
3437
3599
|
"upsert_views[].query_conditions.rows is a layout matrix of field names; it is compiled to backend queryCondition queIds",
|
|
3600
|
+
"use patch_views for partial parameter replacement on existing views; the public update mode is patch even though the backend save is still a full view payload",
|
|
3438
3601
|
"view associated report/view display is now configured through app_associated_resources_apply; app_views_apply keeps legacy associated_resources input compatible but it is no longer the recommended public contract",
|
|
3439
3602
|
"for multi-value operators such as in, pass values as a list; value may also be used as an alias when it already contains a list",
|
|
3440
3603
|
*_VISIBILITY_EXECUTION_NOTES,
|
|
@@ -3447,6 +3610,23 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3447
3610
|
"remove_views": [],
|
|
3448
3611
|
},
|
|
3449
3612
|
"query_conditions_example": {
|
|
3613
|
+
"profile": "default",
|
|
3614
|
+
"app_key": "APP_KEY",
|
|
3615
|
+
"publish": True,
|
|
3616
|
+
"patch_views": [
|
|
3617
|
+
{
|
|
3618
|
+
"view_key": "VIEW_KEY",
|
|
3619
|
+
"set": {
|
|
3620
|
+
"query_conditions": {
|
|
3621
|
+
"enabled": True,
|
|
3622
|
+
"rows": [["客户名称", "负责人"], ["创建时间"]],
|
|
3623
|
+
}
|
|
3624
|
+
},
|
|
3625
|
+
}
|
|
3626
|
+
],
|
|
3627
|
+
"remove_views": [],
|
|
3628
|
+
},
|
|
3629
|
+
"full_upsert_query_conditions_example": {
|
|
3450
3630
|
"profile": "default",
|
|
3451
3631
|
"app_key": "APP_KEY",
|
|
3452
3632
|
"publish": True,
|
|
@@ -3496,7 +3676,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3496
3676
|
"can_edit_form covers form/schema routes only and does not imply app base-info writes",
|
|
3497
3677
|
"returns normalized app visibility when backend auth is readable",
|
|
3498
3678
|
"custom_buttons[].button_id is the id required by app_custom_buttons_apply view_configs[].buttons[].button_ref",
|
|
3499
|
-
"associated_resources[].associated_item_id is the id
|
|
3679
|
+
"associated_resources[].associated_item_id is the internal id; app_associated_resources_apply.view_configs/remove/reorder may also pass an existing resource's chart_id/chart_key/view_key",
|
|
3500
3680
|
],
|
|
3501
3681
|
"minimal_example": {
|
|
3502
3682
|
"profile": "default",
|
|
@@ -3604,8 +3784,9 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3604
3784
|
},
|
|
3605
3785
|
},
|
|
3606
3786
|
"app_charts_apply": {
|
|
3607
|
-
"allowed_keys": ["app_key", "upsert_charts", "remove_chart_ids", "reorder_chart_ids", "upsert_charts[].visibility"],
|
|
3787
|
+
"allowed_keys": ["app_key", "upsert_charts", "patch_charts", "remove_chart_ids", "reorder_chart_ids", "upsert_charts[].visibility", "patch_charts[].chart_id", "patch_charts[].name", "patch_charts[].set", "patch_charts[].unset"],
|
|
3608
3788
|
"aliases": {
|
|
3789
|
+
"patchCharts": "patch_charts",
|
|
3609
3790
|
"chart.id": "chart.chart_id",
|
|
3610
3791
|
"chart.type": "chart.chart_type",
|
|
3611
3792
|
"chart.dimension_fields": "chart.dimension_field_ids",
|
|
@@ -3619,7 +3800,12 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3619
3800
|
**deepcopy(_VISIBILITY_ALLOWED_VALUES),
|
|
3620
3801
|
},
|
|
3621
3802
|
"execution_notes": [
|
|
3803
|
+
"this tool manages QingBI report bodies/configs; it does not attach reports to Qingflow app associated-resource display",
|
|
3804
|
+
"app_charts_apply creates/updates app-source QingBI reports only; generated payloads use dataSourceType=qingflow",
|
|
3805
|
+
"dataset BI reports are not created or edited by this tool yet; create them in QingBI first, then attach the existing report with app_associated_resources_apply report_source=dataset",
|
|
3806
|
+
"after creating or updating an app-source report body, use app_associated_resources_apply when the report should appear inside a Qingflow app/view",
|
|
3622
3807
|
"app_charts_apply is immediate-live and does not publish",
|
|
3808
|
+
"use patch_charts for partial parameter replacement on existing charts; the tool reads current chart base/config, merges patch_charts[].set/unset, then submits full QingBI base/config payloads internally",
|
|
3623
3809
|
"chart matching precedence is chart_id first, then exact unique chart name",
|
|
3624
3810
|
"when chart names are not unique, supply chart_id instead of guessing by name",
|
|
3625
3811
|
"successful create results must return a real backend chart_id",
|
|
@@ -3631,6 +3817,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3631
3817
|
"profile": "default",
|
|
3632
3818
|
"app_key": "APP_KEY",
|
|
3633
3819
|
"upsert_charts": [{"name": "数据总量", "chart_type": "target", "indicator_field_ids": [], "visibility": deepcopy(_VISIBILITY_WORKSPACE_EXAMPLE)}],
|
|
3820
|
+
"patch_charts": [{"chart_id": "CHART_ID", "set": {"name": "数据总量-新版"}}],
|
|
3634
3821
|
"remove_chart_ids": [],
|
|
3635
3822
|
"reorder_chart_ids": [],
|
|
3636
3823
|
},
|
|
@@ -3642,6 +3829,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3642
3829
|
"execution_notes": [
|
|
3643
3830
|
"returns one builder-side view definition detail",
|
|
3644
3831
|
"does not return record data; use user-side view_get or record_list for runtime rows",
|
|
3832
|
+
"view_key is a raw builder view key; if a record-data custom:VIEW_KEY value is passed, the tool normalizes it to VIEW_KEY",
|
|
3645
3833
|
"use this after builder portal_get when a component references a view_ref.view_key",
|
|
3646
3834
|
"returns normalized view visibility when backend auth is readable",
|
|
3647
3835
|
],
|
|
@@ -3688,6 +3876,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
3688
3876
|
"create mode: package_id + dash_name",
|
|
3689
3877
|
"portal_apply uses replace semantics for sections",
|
|
3690
3878
|
"when editing an existing portal, sections may be omitted to update only base info such as visibility, icon, or package",
|
|
3879
|
+
"portal section-level patch is not exposed; supplying sections means full sections replacement",
|
|
3691
3880
|
"remove a section by omitting it from the new sections list",
|
|
3692
3881
|
"package_id is required when creating a new portal",
|
|
3693
3882
|
"publish=false only guarantees draft and base-info updates; it does not claim live has changed",
|