@josephyan/qingflow-app-builder-mcp 0.2.0-beta.49 → 0.2.0-beta.50
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/src/qingflow_mcp/builder_facade/models.py +61 -5
- package/src/qingflow_mcp/builder_facade/service.py +525 -20
- package/src/qingflow_mcp/tools/ai_builder_tools.py +51 -0
- package/src/qingflow_mcp/tools/app_tools.py +36 -0
- package/src/qingflow_mcp/tools/code_block_tools.py +18 -3
- package/src/qingflow_mcp/tools/record_tools.py +735 -90
|
@@ -25,6 +25,7 @@ from ..builder_facade.models import (
|
|
|
25
25
|
LayoutSectionPatch,
|
|
26
26
|
PortalApplyRequest,
|
|
27
27
|
PublicFieldType,
|
|
28
|
+
PublicRelationMode,
|
|
28
29
|
PublicChartType,
|
|
29
30
|
PublicViewType,
|
|
30
31
|
SchemaPlanRequest,
|
|
@@ -1596,9 +1597,17 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
1596
1597
|
"field.label": "field.name",
|
|
1597
1598
|
"field.fields": "field.subfields",
|
|
1598
1599
|
"field.type_id": "field.type",
|
|
1600
|
+
"field.relationMode": "field.relation_mode",
|
|
1601
|
+
"field.selection_mode": "field.relation_mode",
|
|
1602
|
+
"field.selectionMode": "field.relation_mode",
|
|
1603
|
+
"field.multiple": "field.relation_mode",
|
|
1604
|
+
"field.allow_multiple": "field.relation_mode",
|
|
1605
|
+
"field.optional_data_num": "field.relation_mode",
|
|
1606
|
+
"field.optionalDataNum": "field.relation_mode",
|
|
1599
1607
|
},
|
|
1600
1608
|
"allowed_values": {
|
|
1601
1609
|
"field.type": [member.value for member in PublicFieldType],
|
|
1610
|
+
"field.relation_mode": [member.value for member in PublicRelationMode],
|
|
1602
1611
|
"field_type_ids": sorted(FIELD_TYPE_ID_ALIASES.keys()),
|
|
1603
1612
|
},
|
|
1604
1613
|
"minimal_example": {
|
|
@@ -1610,6 +1619,22 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
1610
1619
|
"update_fields": [],
|
|
1611
1620
|
"remove_fields": [],
|
|
1612
1621
|
},
|
|
1622
|
+
"relation_example": {
|
|
1623
|
+
"profile": "default",
|
|
1624
|
+
"app_key": "APP_ITERATION",
|
|
1625
|
+
"add_fields": [
|
|
1626
|
+
{
|
|
1627
|
+
"name": "需求反馈引用",
|
|
1628
|
+
"type": "relation",
|
|
1629
|
+
"target_app_key": "APP_FEEDBACK",
|
|
1630
|
+
"relation_mode": "multiple",
|
|
1631
|
+
"display_field": {"name": "反馈标题"},
|
|
1632
|
+
"visible_fields": [{"name": "反馈标题"}, {"name": "优先级判断"}],
|
|
1633
|
+
}
|
|
1634
|
+
],
|
|
1635
|
+
"update_fields": [],
|
|
1636
|
+
"remove_fields": [],
|
|
1637
|
+
},
|
|
1613
1638
|
},
|
|
1614
1639
|
"app_schema_apply": {
|
|
1615
1640
|
"allowed_keys": ["app_key", "package_tag_id", "app_name", "create_if_missing", "publish", "add_fields", "update_fields", "remove_fields"],
|
|
@@ -1620,14 +1645,23 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
1620
1645
|
"field.label": "field.name",
|
|
1621
1646
|
"field.fields": "field.subfields",
|
|
1622
1647
|
"field.type_id": "field.type",
|
|
1648
|
+
"field.relationMode": "field.relation_mode",
|
|
1649
|
+
"field.selection_mode": "field.relation_mode",
|
|
1650
|
+
"field.selectionMode": "field.relation_mode",
|
|
1651
|
+
"field.multiple": "field.relation_mode",
|
|
1652
|
+
"field.allow_multiple": "field.relation_mode",
|
|
1653
|
+
"field.optional_data_num": "field.relation_mode",
|
|
1654
|
+
"field.optionalDataNum": "field.relation_mode",
|
|
1623
1655
|
},
|
|
1624
1656
|
"allowed_values": {
|
|
1625
1657
|
"field.type": [member.value for member in PublicFieldType],
|
|
1658
|
+
"field.relation_mode": [member.value for member in PublicRelationMode],
|
|
1626
1659
|
"field_type_ids": sorted(FIELD_TYPE_ID_ALIASES.keys()),
|
|
1627
1660
|
},
|
|
1628
1661
|
"execution_notes": [
|
|
1629
1662
|
"multiple relation fields are backend-risky; read verification.relation_field_limit_verified and warnings before declaring the schema stable",
|
|
1630
1663
|
"backend 49614 is normalized to MULTIPLE_RELATION_FIELDS_UNSUPPORTED with a workaround message",
|
|
1664
|
+
"relation_mode=multiple maps to referenceConfig.optionalDataNum=0",
|
|
1631
1665
|
],
|
|
1632
1666
|
"minimal_example": {
|
|
1633
1667
|
"profile": "default",
|
|
@@ -1639,6 +1673,23 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
1639
1673
|
"update_fields": [],
|
|
1640
1674
|
"remove_fields": [],
|
|
1641
1675
|
},
|
|
1676
|
+
"relation_example": {
|
|
1677
|
+
"profile": "default",
|
|
1678
|
+
"app_key": "APP_ITERATION",
|
|
1679
|
+
"publish": True,
|
|
1680
|
+
"add_fields": [
|
|
1681
|
+
{
|
|
1682
|
+
"name": "需求反馈引用",
|
|
1683
|
+
"type": "relation",
|
|
1684
|
+
"target_app_key": "APP_FEEDBACK",
|
|
1685
|
+
"relation_mode": "multiple",
|
|
1686
|
+
"display_field": {"name": "反馈标题"},
|
|
1687
|
+
"visible_fields": [{"name": "反馈标题"}, {"name": "优先级判断"}],
|
|
1688
|
+
}
|
|
1689
|
+
],
|
|
1690
|
+
"update_fields": [],
|
|
1691
|
+
"remove_fields": [],
|
|
1692
|
+
},
|
|
1642
1693
|
},
|
|
1643
1694
|
"app_layout_plan": {
|
|
1644
1695
|
"allowed_keys": ["app_key", "mode", "sections", "preset"],
|
|
@@ -268,6 +268,42 @@ class AppTools(ToolBase):
|
|
|
268
268
|
|
|
269
269
|
return self._run(profile, runner)
|
|
270
270
|
|
|
271
|
+
def app_get_apply_base_info(self, *, profile: str, app_key: str, list_type: int) -> JSONObject:
|
|
272
|
+
self._require_app_key(app_key)
|
|
273
|
+
if not isinstance(list_type, int) or isinstance(list_type, bool) or list_type <= 0:
|
|
274
|
+
raise_tool_error(QingflowApiError.config_error("list_type must be a positive integer"))
|
|
275
|
+
|
|
276
|
+
def runner(session_profile, context):
|
|
277
|
+
result = self.backend.request("GET", context, f"/app/{app_key}/apply/baseInfo", params={"type": list_type})
|
|
278
|
+
return {
|
|
279
|
+
"profile": profile,
|
|
280
|
+
"ws_id": session_profile.selected_ws_id,
|
|
281
|
+
"app_key": app_key,
|
|
282
|
+
"list_type": list_type,
|
|
283
|
+
"result": result,
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return self._run(profile, runner)
|
|
287
|
+
|
|
288
|
+
def app_update_apply_config(self, *, profile: str, app_key: str, payload: JSONObject) -> JSONObject:
|
|
289
|
+
self._require_app_key(app_key)
|
|
290
|
+
body = self._require_dict(payload)
|
|
291
|
+
|
|
292
|
+
def runner(session_profile, context):
|
|
293
|
+
result = self.backend.request("POST", context, f"/app/{app_key}/apply/config", json_body=body)
|
|
294
|
+
return self._attach_human_review_notice(
|
|
295
|
+
{
|
|
296
|
+
"profile": profile,
|
|
297
|
+
"ws_id": session_profile.selected_ws_id,
|
|
298
|
+
"app_key": app_key,
|
|
299
|
+
"result": result,
|
|
300
|
+
},
|
|
301
|
+
operation="update",
|
|
302
|
+
target="app apply list configuration",
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
return self._run(profile, runner)
|
|
306
|
+
|
|
271
307
|
def app_update_form_schema(self, *, profile: str, app_key: str, payload: JSONObject) -> JSONObject:
|
|
272
308
|
self._require_app_key(app_key)
|
|
273
309
|
body = self._require_dict(payload)
|
|
@@ -149,7 +149,7 @@ class CodeBlockTools(RecordTools):
|
|
|
149
149
|
run_result = self.backend.request(
|
|
150
150
|
"POST",
|
|
151
151
|
context,
|
|
152
|
-
f"/
|
|
152
|
+
f"/data/{app_key}/codeBlock/working",
|
|
153
153
|
json_body=run_body,
|
|
154
154
|
)
|
|
155
155
|
alias_results = _normalize_code_block_alias_results(run_result)
|
|
@@ -173,8 +173,22 @@ class CodeBlockTools(RecordTools):
|
|
|
173
173
|
}
|
|
174
174
|
if workflow_node_id is not None:
|
|
175
175
|
relation_body["auditNodeId"] = workflow_node_id
|
|
176
|
-
|
|
177
|
-
|
|
176
|
+
relation_route = "/data/que/actuator"
|
|
177
|
+
try:
|
|
178
|
+
relation_result = self.backend.request("POST", context, relation_route, json_body=relation_body)
|
|
179
|
+
relation_items = _relation_result_items(relation_result)
|
|
180
|
+
except QingflowApiError as exc:
|
|
181
|
+
if exc.http_status != 404:
|
|
182
|
+
raise
|
|
183
|
+
relation_route = "/que/actuator"
|
|
184
|
+
relation_result = self.backend.request("POST", context, relation_route, json_body=relation_body)
|
|
185
|
+
relation_items = _relation_result_items(relation_result)
|
|
186
|
+
if not relation_items:
|
|
187
|
+
# Keep compatibility with legacy runtime deployments and lightweight test doubles
|
|
188
|
+
# that still stub the older relation-calculation route only.
|
|
189
|
+
relation_route = "/que/actuator"
|
|
190
|
+
relation_result = self.backend.request("POST", context, relation_route, json_body=relation_body)
|
|
191
|
+
relation_items = _relation_result_items(relation_result)
|
|
178
192
|
relation_errors = _relation_result_errors(relation_items)
|
|
179
193
|
calculated_answers = _relation_result_answers(relation_items)
|
|
180
194
|
write_result: JSONObject | None = None
|
|
@@ -256,6 +270,7 @@ class CodeBlockTools(RecordTools):
|
|
|
256
270
|
if normalized_output_profile == "verbose":
|
|
257
271
|
response["debug"] = {
|
|
258
272
|
"run_body": run_body,
|
|
273
|
+
"relation_route": relation_route if relation_target_fields else None,
|
|
259
274
|
"relation_result": relation_result,
|
|
260
275
|
"calculated_answers": calculated_answers,
|
|
261
276
|
"merged_answers": merged_answers,
|