@josephyan/qingflow-cli 0.2.0-beta.71 → 0.2.0-beta.72
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/backend_client.py +1 -0
- package/src/qingflow_mcp/builder_facade/models.py +16 -8
- package/src/qingflow_mcp/builder_facade/service.py +183 -121
- package/src/qingflow_mcp/cli/commands/__init__.py +4 -1
- package/src/qingflow_mcp/cli/commands/builder.py +24 -64
- package/src/qingflow_mcp/cli/commands/chart.py +18 -0
- package/src/qingflow_mcp/cli/commands/portal.py +25 -0
- package/src/qingflow_mcp/cli/commands/view.py +18 -0
- package/src/qingflow_mcp/cli/context.py +3 -0
- package/src/qingflow_mcp/response_trim.py +211 -178
- package/src/qingflow_mcp/server_app_builder.py +18 -42
- package/src/qingflow_mcp/server_app_user.py +21 -1
- package/src/qingflow_mcp/tools/ai_builder_tools.py +165 -124
- package/src/qingflow_mcp/tools/app_tools.py +0 -4
- package/src/qingflow_mcp/tools/resource_read_tools.py +399 -0
|
@@ -1079,7 +1079,7 @@ class AiBuilderFacade:
|
|
|
1079
1079
|
api_error,
|
|
1080
1080
|
normalized_args=normalized_args,
|
|
1081
1081
|
details={"app_key": app_key},
|
|
1082
|
-
suggested_next_call={"tool_name": "
|
|
1082
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
1083
1083
|
)
|
|
1084
1084
|
edit_version_no = _coerce_positive_int(version_result.get("editVersionNo") or version_result.get("versionNo")) or 1
|
|
1085
1085
|
try:
|
|
@@ -1114,7 +1114,7 @@ class AiBuilderFacade:
|
|
|
1114
1114
|
"edit_version_no": edit_version_no,
|
|
1115
1115
|
},
|
|
1116
1116
|
"request_id": None,
|
|
1117
|
-
"suggested_next_call": {"tool_name": "
|
|
1117
|
+
"suggested_next_call": {"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
1118
1118
|
"noop": False,
|
|
1119
1119
|
"verification": {"released": True},
|
|
1120
1120
|
"app_key": app_key,
|
|
@@ -1154,7 +1154,7 @@ class AiBuilderFacade:
|
|
|
1154
1154
|
"permission_check_skipped": True,
|
|
1155
1155
|
},
|
|
1156
1156
|
"request_id": api_error.request_id,
|
|
1157
|
-
"suggested_next_call": {"tool_name": "
|
|
1157
|
+
"suggested_next_call": {"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
1158
1158
|
"noop": False,
|
|
1159
1159
|
"warnings": [
|
|
1160
1160
|
_warning(
|
|
@@ -1174,7 +1174,7 @@ class AiBuilderFacade:
|
|
|
1174
1174
|
"APP_NOT_FOUND" if api_error.http_status == 404 else "APP_RESOLVE_FAILED",
|
|
1175
1175
|
api_error,
|
|
1176
1176
|
details={"app_key": app_key},
|
|
1177
|
-
suggested_next_call={"tool_name": "
|
|
1177
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
1178
1178
|
)
|
|
1179
1179
|
result = base.get("result") if isinstance(base.get("result"), dict) else {}
|
|
1180
1180
|
return {
|
|
@@ -1852,7 +1852,7 @@ class AiBuilderFacade:
|
|
|
1852
1852
|
"category": api_error.category,
|
|
1853
1853
|
},
|
|
1854
1854
|
},
|
|
1855
|
-
suggested_next_call={"tool_name": "
|
|
1855
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
1856
1856
|
request_id=api_error.request_id,
|
|
1857
1857
|
backend_code=api_error.backend_code,
|
|
1858
1858
|
http_status=None if api_error.http_status == 404 else api_error.http_status,
|
|
@@ -1890,7 +1890,7 @@ class AiBuilderFacade:
|
|
|
1890
1890
|
"required_permission": required_permission,
|
|
1891
1891
|
"permission_summary": permission_summary,
|
|
1892
1892
|
},
|
|
1893
|
-
suggested_next_call={"tool_name": "
|
|
1893
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
1894
1894
|
)
|
|
1895
1895
|
)
|
|
1896
1896
|
|
|
@@ -2003,7 +2003,7 @@ class AiBuilderFacade:
|
|
|
2003
2003
|
"current user does not have builder edit permission on this portal",
|
|
2004
2004
|
normalized_args=normalized_args,
|
|
2005
2005
|
details={"dash_key": dash_key, "permission_summary": permission_summary},
|
|
2006
|
-
suggested_next_call={"tool_name": "
|
|
2006
|
+
suggested_next_call={"tool_name": "portal_get", "arguments": {"profile": profile, "dash_key": dash_key}},
|
|
2007
2007
|
)
|
|
2008
2008
|
)
|
|
2009
2009
|
|
|
@@ -2066,6 +2066,52 @@ class AiBuilderFacade:
|
|
|
2066
2066
|
**response.model_dump(mode="json"),
|
|
2067
2067
|
}
|
|
2068
2068
|
|
|
2069
|
+
def app_get(self, *, profile: str, app_key: str) -> JSONObject:
|
|
2070
|
+
result = self.app_read_summary(profile=profile, app_key=app_key)
|
|
2071
|
+
if result.get("status") != "success":
|
|
2072
|
+
if not result.get("suggested_next_call"):
|
|
2073
|
+
result["suggested_next_call"] = {"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}}
|
|
2074
|
+
return result
|
|
2075
|
+
permission_summary = self._read_app_permission_summary(profile=profile, app_key=app_key)
|
|
2076
|
+
result["message"] = "read app config summary"
|
|
2077
|
+
result["editability"] = {
|
|
2078
|
+
"can_edit_form": permission_summary.get("can_edit_app"),
|
|
2079
|
+
"can_edit_flow": permission_summary.get("can_edit_app"),
|
|
2080
|
+
"can_edit_views": permission_summary.get("can_manage_data"),
|
|
2081
|
+
"can_edit_charts": permission_summary.get("can_manage_data"),
|
|
2082
|
+
}
|
|
2083
|
+
return result
|
|
2084
|
+
|
|
2085
|
+
def app_get_fields(self, *, profile: str, app_key: str) -> JSONObject:
|
|
2086
|
+
result = self.app_read_fields(profile=profile, app_key=app_key)
|
|
2087
|
+
if result.get("status") == "success":
|
|
2088
|
+
result["message"] = "read app field config"
|
|
2089
|
+
return result
|
|
2090
|
+
|
|
2091
|
+
def app_get_layout(self, *, profile: str, app_key: str) -> JSONObject:
|
|
2092
|
+
result = self.app_read_layout_summary(profile=profile, app_key=app_key)
|
|
2093
|
+
if result.get("status") == "success":
|
|
2094
|
+
result["message"] = "read app layout config"
|
|
2095
|
+
return result
|
|
2096
|
+
|
|
2097
|
+
def app_get_views(self, *, profile: str, app_key: str) -> JSONObject:
|
|
2098
|
+
result = self.app_read_views_summary(profile=profile, app_key=app_key)
|
|
2099
|
+
if result.get("status") == "success":
|
|
2100
|
+
result["message"] = "read app view config"
|
|
2101
|
+
return result
|
|
2102
|
+
|
|
2103
|
+
def app_get_flow(self, *, profile: str, app_key: str) -> JSONObject:
|
|
2104
|
+
result = self.app_read_flow_summary(profile=profile, app_key=app_key)
|
|
2105
|
+
if result.get("status") == "success":
|
|
2106
|
+
result["message"] = "read app flow config"
|
|
2107
|
+
return result
|
|
2108
|
+
|
|
2109
|
+
def app_get_charts(self, *, profile: str, app_key: str) -> JSONObject:
|
|
2110
|
+
result = self.app_read_charts_summary(profile=profile, app_key=app_key)
|
|
2111
|
+
if result.get("status") == "success":
|
|
2112
|
+
result["message"] = "read app chart config"
|
|
2113
|
+
return result
|
|
2114
|
+
|
|
2069
2115
|
def app_read_fields(self, *, profile: str, app_key: str) -> JSONObject:
|
|
2070
2116
|
try:
|
|
2071
2117
|
state = self._load_base_schema_state(profile=profile, app_key=app_key)
|
|
@@ -2076,7 +2122,7 @@ class AiBuilderFacade:
|
|
|
2076
2122
|
api_error,
|
|
2077
2123
|
normalized_args={"app_key": app_key},
|
|
2078
2124
|
details={"app_key": app_key},
|
|
2079
|
-
suggested_next_call={"tool_name": "
|
|
2125
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
2080
2126
|
)
|
|
2081
2127
|
parsed = state["parsed"]
|
|
2082
2128
|
response = AppFieldsReadResponse(
|
|
@@ -2112,7 +2158,7 @@ class AiBuilderFacade:
|
|
|
2112
2158
|
api_error,
|
|
2113
2159
|
normalized_args={"app_key": app_key},
|
|
2114
2160
|
details={"app_key": app_key},
|
|
2115
|
-
suggested_next_call={"tool_name": "
|
|
2161
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
2116
2162
|
)
|
|
2117
2163
|
parsed = state["parsed"]
|
|
2118
2164
|
layout = parsed["layout"]
|
|
@@ -2157,7 +2203,7 @@ class AiBuilderFacade:
|
|
|
2157
2203
|
api_error,
|
|
2158
2204
|
normalized_args={"app_key": app_key},
|
|
2159
2205
|
details={"app_key": app_key},
|
|
2160
|
-
suggested_next_call={"tool_name": "
|
|
2206
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
2161
2207
|
)
|
|
2162
2208
|
summarized_views, config_read_errors = _summarize_views_with_config(self.views, profile=profile, views=views)
|
|
2163
2209
|
response = AppViewsReadResponse(
|
|
@@ -2211,7 +2257,7 @@ class AiBuilderFacade:
|
|
|
2211
2257
|
api_error,
|
|
2212
2258
|
normalized_args={"app_key": app_key},
|
|
2213
2259
|
details={"app_key": app_key},
|
|
2214
|
-
suggested_next_call={"tool_name": "
|
|
2260
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
2215
2261
|
)
|
|
2216
2262
|
response = AppFlowReadResponse(
|
|
2217
2263
|
app_key=app_key,
|
|
@@ -2251,7 +2297,7 @@ class AiBuilderFacade:
|
|
|
2251
2297
|
api_error,
|
|
2252
2298
|
normalized_args={"app_key": app_key},
|
|
2253
2299
|
details={"app_key": app_key},
|
|
2254
|
-
suggested_next_call={"tool_name": "
|
|
2300
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
2255
2301
|
)
|
|
2256
2302
|
charts = _summarize_charts(items)
|
|
2257
2303
|
response = AppChartsReadResponse(
|
|
@@ -2289,13 +2335,54 @@ class AiBuilderFacade:
|
|
|
2289
2335
|
details={},
|
|
2290
2336
|
suggested_next_call=None,
|
|
2291
2337
|
)
|
|
2292
|
-
|
|
2338
|
+
warnings: list[dict[str, Any]] = []
|
|
2339
|
+
items: list[dict[str, Any]] = []
|
|
2340
|
+
permission_verified = True
|
|
2341
|
+
for raw_item in raw_items if isinstance(raw_items, list) else []:
|
|
2342
|
+
if not isinstance(raw_item, dict):
|
|
2343
|
+
continue
|
|
2344
|
+
dash_key = str(raw_item.get("dashKey") or "").strip()
|
|
2345
|
+
if not dash_key:
|
|
2346
|
+
continue
|
|
2347
|
+
try:
|
|
2348
|
+
portal_result = self.portals.portal_get(profile=profile, dash_key=dash_key, being_draft=True).get("result") or {}
|
|
2349
|
+
except (QingflowApiError, RuntimeError):
|
|
2350
|
+
permission_verified = False
|
|
2351
|
+
warnings.append(
|
|
2352
|
+
_warning(
|
|
2353
|
+
"PORTAL_PERMISSION_READ_UNAVAILABLE",
|
|
2354
|
+
f"builder portal_list skipped `{dash_key}` because portal detail readback was unavailable during permission verification",
|
|
2355
|
+
dash_key=dash_key,
|
|
2356
|
+
)
|
|
2357
|
+
)
|
|
2358
|
+
continue
|
|
2359
|
+
permission_outcome = self._guard_portal_permission(
|
|
2360
|
+
profile=profile,
|
|
2361
|
+
dash_key=dash_key,
|
|
2362
|
+
normalized_args={"dash_key": dash_key},
|
|
2363
|
+
portal_result=portal_result if isinstance(portal_result, dict) else {},
|
|
2364
|
+
)
|
|
2365
|
+
if permission_outcome.block is not None:
|
|
2366
|
+
error_code = str(permission_outcome.block.get("error_code") or "")
|
|
2367
|
+
if error_code != "PORTAL_EDIT_UNAUTHORIZED":
|
|
2368
|
+
permission_verified = False
|
|
2369
|
+
warnings.append(
|
|
2370
|
+
_warning(
|
|
2371
|
+
"PORTAL_PERMISSION_UNVERIFIED",
|
|
2372
|
+
f"builder portal_list skipped `{dash_key}` because builder edit permission could not be verified",
|
|
2373
|
+
dash_key=dash_key,
|
|
2374
|
+
)
|
|
2375
|
+
)
|
|
2376
|
+
continue
|
|
2377
|
+
normalized = _normalize_portal_list_items([raw_item])
|
|
2378
|
+
if normalized:
|
|
2379
|
+
items.extend(normalized)
|
|
2293
2380
|
response = PortalListResponse(items=items, total=len(items))
|
|
2294
2381
|
return {
|
|
2295
2382
|
"status": "success",
|
|
2296
2383
|
"error_code": None,
|
|
2297
2384
|
"recoverable": False,
|
|
2298
|
-
"message": "list
|
|
2385
|
+
"message": "list builder-configurable portals",
|
|
2299
2386
|
"normalized_args": {},
|
|
2300
2387
|
"missing_fields": [],
|
|
2301
2388
|
"allowed_values": {},
|
|
@@ -2303,9 +2390,12 @@ class AiBuilderFacade:
|
|
|
2303
2390
|
"request_id": None,
|
|
2304
2391
|
"suggested_next_call": None,
|
|
2305
2392
|
"noop": False,
|
|
2306
|
-
"warnings":
|
|
2307
|
-
"verification": {
|
|
2308
|
-
|
|
2393
|
+
"warnings": warnings,
|
|
2394
|
+
"verification": {
|
|
2395
|
+
"portal_list_loaded": True,
|
|
2396
|
+
"portal_permissions_verified": permission_verified,
|
|
2397
|
+
},
|
|
2398
|
+
"verified": permission_verified,
|
|
2309
2399
|
**response.model_dump(mode="json"),
|
|
2310
2400
|
}
|
|
2311
2401
|
|
|
@@ -2380,7 +2470,7 @@ class AiBuilderFacade:
|
|
|
2380
2470
|
api_error,
|
|
2381
2471
|
normalized_args={"dash_key": dash_key, "being_draft": being_draft},
|
|
2382
2472
|
details={"dash_key": dash_key, "being_draft": being_draft},
|
|
2383
|
-
suggested_next_call={"tool_name": "
|
|
2473
|
+
suggested_next_call={"tool_name": "portal_get", "arguments": {"profile": profile, "dash_key": dash_key, "being_draft": being_draft}},
|
|
2384
2474
|
)
|
|
2385
2475
|
response = PortalReadSummaryResponse(
|
|
2386
2476
|
dash_key=dash_key,
|
|
@@ -2420,17 +2510,17 @@ class AiBuilderFacade:
|
|
|
2420
2510
|
**response.model_dump(mode="json"),
|
|
2421
2511
|
}
|
|
2422
2512
|
|
|
2423
|
-
def view_get(self, *, profile: str,
|
|
2513
|
+
def view_get(self, *, profile: str, view_key: str) -> JSONObject:
|
|
2424
2514
|
try:
|
|
2425
|
-
config = self.views.view_get_config(profile=profile, viewgraph_key=
|
|
2515
|
+
config = self.views.view_get_config(profile=profile, viewgraph_key=view_key).get("result") or {}
|
|
2426
2516
|
except (QingflowApiError, RuntimeError) as error:
|
|
2427
2517
|
api_error = _coerce_api_error(error)
|
|
2428
2518
|
return _failed_from_api_error(
|
|
2429
2519
|
"VIEW_GET_FAILED",
|
|
2430
2520
|
api_error,
|
|
2431
|
-
normalized_args={"
|
|
2432
|
-
details={"
|
|
2433
|
-
suggested_next_call={"tool_name": "view_get", "arguments": {"profile": profile, "
|
|
2521
|
+
normalized_args={"view_key": view_key},
|
|
2522
|
+
details={"view_key": view_key},
|
|
2523
|
+
suggested_next_call={"tool_name": "view_get", "arguments": {"profile": profile, "view_key": view_key}},
|
|
2434
2524
|
)
|
|
2435
2525
|
|
|
2436
2526
|
warnings: list[dict[str, Any]] = []
|
|
@@ -2443,7 +2533,7 @@ class AiBuilderFacade:
|
|
|
2443
2533
|
|
|
2444
2534
|
base_info: dict[str, Any] = {}
|
|
2445
2535
|
try:
|
|
2446
|
-
base_info_payload = self.views.view_get_base_info(profile=profile, viewgraph_key=
|
|
2536
|
+
base_info_payload = self.views.view_get_base_info(profile=profile, viewgraph_key=view_key, passcode=None).get("result") or {}
|
|
2447
2537
|
if isinstance(base_info_payload, dict):
|
|
2448
2538
|
base_info = deepcopy(base_info_payload)
|
|
2449
2539
|
except (QingflowApiError, RuntimeError):
|
|
@@ -2452,7 +2542,7 @@ class AiBuilderFacade:
|
|
|
2452
2542
|
|
|
2453
2543
|
questions: list[dict[str, Any]] = []
|
|
2454
2544
|
try:
|
|
2455
|
-
questions_payload = self.views.view_list_questions(profile=profile, viewgraph_key=
|
|
2545
|
+
questions_payload = self.views.view_list_questions(profile=profile, viewgraph_key=view_key).get("result") or []
|
|
2456
2546
|
if isinstance(questions_payload, list):
|
|
2457
2547
|
questions = [deepcopy(item) for item in questions_payload if isinstance(item, dict)]
|
|
2458
2548
|
except (QingflowApiError, RuntimeError):
|
|
@@ -2461,7 +2551,7 @@ class AiBuilderFacade:
|
|
|
2461
2551
|
|
|
2462
2552
|
associations: list[dict[str, Any]] = []
|
|
2463
2553
|
try:
|
|
2464
|
-
associations_payload = self.views.view_list_associations(profile=profile, viewgraph_key=
|
|
2554
|
+
associations_payload = self.views.view_list_associations(profile=profile, viewgraph_key=view_key).get("result") or []
|
|
2465
2555
|
if isinstance(associations_payload, list):
|
|
2466
2556
|
associations = [deepcopy(item) for item in associations_payload if isinstance(item, dict)]
|
|
2467
2557
|
except (QingflowApiError, RuntimeError):
|
|
@@ -2469,7 +2559,7 @@ class AiBuilderFacade:
|
|
|
2469
2559
|
warnings.append(_warning("VIEW_ASSOCIATIONS_UNAVAILABLE", "view association list readback is unavailable"))
|
|
2470
2560
|
|
|
2471
2561
|
response = ViewGetResponse(
|
|
2472
|
-
|
|
2562
|
+
view_key=view_key,
|
|
2473
2563
|
base_info=base_info,
|
|
2474
2564
|
config=deepcopy(config) if isinstance(config, dict) else {},
|
|
2475
2565
|
questions=questions,
|
|
@@ -2480,7 +2570,7 @@ class AiBuilderFacade:
|
|
|
2480
2570
|
"error_code": None,
|
|
2481
2571
|
"recoverable": False,
|
|
2482
2572
|
"message": "read view detail",
|
|
2483
|
-
"normalized_args": {"
|
|
2573
|
+
"normalized_args": {"view_key": view_key},
|
|
2484
2574
|
"missing_fields": [],
|
|
2485
2575
|
"allowed_values": {},
|
|
2486
2576
|
"details": {},
|
|
@@ -2498,43 +2588,20 @@ class AiBuilderFacade:
|
|
|
2498
2588
|
*,
|
|
2499
2589
|
profile: str,
|
|
2500
2590
|
chart_id: str,
|
|
2501
|
-
data_payload: dict[str, Any] | None = None,
|
|
2502
|
-
page_num: int | None = None,
|
|
2503
|
-
page_size: int | None = None,
|
|
2504
|
-
page_num_y: int | None = None,
|
|
2505
|
-
page_size_y: int | None = None,
|
|
2506
2591
|
) -> JSONObject:
|
|
2507
|
-
normalized_payload = deepcopy(data_payload) if isinstance(data_payload, dict) else {}
|
|
2508
2592
|
warnings: list[dict[str, Any]] = []
|
|
2509
2593
|
verification = {
|
|
2510
2594
|
"chart_exists": True,
|
|
2511
|
-
"chart_data_loaded": True,
|
|
2512
2595
|
"chart_config_loaded": True,
|
|
2513
2596
|
}
|
|
2514
2597
|
try:
|
|
2515
2598
|
base = self.charts.qingbi_report_get_base(profile=profile, chart_id=chart_id).get("result") or {}
|
|
2516
|
-
data = self.charts.qingbi_report_get_data(
|
|
2517
|
-
profile=profile,
|
|
2518
|
-
chart_id=chart_id,
|
|
2519
|
-
payload=normalized_payload,
|
|
2520
|
-
page_num=page_num,
|
|
2521
|
-
page_size=page_size,
|
|
2522
|
-
page_num_y=page_num_y,
|
|
2523
|
-
page_size_y=page_size_y,
|
|
2524
|
-
).get("result") or {}
|
|
2525
2599
|
except (QingflowApiError, RuntimeError) as error:
|
|
2526
2600
|
api_error = _coerce_api_error(error)
|
|
2527
2601
|
return _failed_from_api_error(
|
|
2528
2602
|
"CHART_GET_FAILED",
|
|
2529
2603
|
api_error,
|
|
2530
|
-
normalized_args={
|
|
2531
|
-
"chart_id": chart_id,
|
|
2532
|
-
"data_payload": normalized_payload,
|
|
2533
|
-
"page_num": page_num,
|
|
2534
|
-
"page_size": page_size,
|
|
2535
|
-
"page_num_y": page_num_y,
|
|
2536
|
-
"page_size_y": page_size_y,
|
|
2537
|
-
},
|
|
2604
|
+
normalized_args={"chart_id": chart_id},
|
|
2538
2605
|
details={"chart_id": chart_id},
|
|
2539
2606
|
suggested_next_call={"tool_name": "chart_get", "arguments": {"profile": profile, "chart_id": chart_id}},
|
|
2540
2607
|
)
|
|
@@ -2542,10 +2609,16 @@ class AiBuilderFacade:
|
|
|
2542
2609
|
try:
|
|
2543
2610
|
config = self.charts.qingbi_report_get_config(profile=profile, chart_id=chart_id).get("result") or {}
|
|
2544
2611
|
except (QingflowApiError, RuntimeError) as error:
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2612
|
+
fallback_config: dict[str, Any] | None = None
|
|
2613
|
+
try:
|
|
2614
|
+
data_fallback = self.charts.qingbi_report_get_data(profile=profile, chart_id=chart_id, payload={}).get("result") or {}
|
|
2615
|
+
config_from_data = data_fallback.get("config") if isinstance(data_fallback, dict) else None
|
|
2616
|
+
if isinstance(config_from_data, dict):
|
|
2617
|
+
fallback_config = deepcopy(config_from_data)
|
|
2618
|
+
except (QingflowApiError, RuntimeError):
|
|
2619
|
+
fallback_config = None
|
|
2620
|
+
if isinstance(fallback_config, dict):
|
|
2621
|
+
config = fallback_config
|
|
2549
2622
|
warnings.append(
|
|
2550
2623
|
_warning(
|
|
2551
2624
|
"CHART_CONFIG_FALLBACK_FROM_DATA",
|
|
@@ -2557,14 +2630,7 @@ class AiBuilderFacade:
|
|
|
2557
2630
|
return _failed_from_api_error(
|
|
2558
2631
|
"CHART_GET_FAILED",
|
|
2559
2632
|
api_error,
|
|
2560
|
-
normalized_args={
|
|
2561
|
-
"chart_id": chart_id,
|
|
2562
|
-
"data_payload": normalized_payload,
|
|
2563
|
-
"page_num": page_num,
|
|
2564
|
-
"page_size": page_size,
|
|
2565
|
-
"page_num_y": page_num_y,
|
|
2566
|
-
"page_size_y": page_size_y,
|
|
2567
|
-
},
|
|
2633
|
+
normalized_args={"chart_id": chart_id},
|
|
2568
2634
|
details={"chart_id": chart_id},
|
|
2569
2635
|
suggested_next_call={"tool_name": "chart_get", "arguments": {"profile": profile, "chart_id": chart_id}},
|
|
2570
2636
|
)
|
|
@@ -2573,21 +2639,13 @@ class AiBuilderFacade:
|
|
|
2573
2639
|
chart_id=chart_id,
|
|
2574
2640
|
base=deepcopy(base) if isinstance(base, dict) else {},
|
|
2575
2641
|
config=deepcopy(config) if isinstance(config, dict) else {},
|
|
2576
|
-
data=deepcopy(data) if isinstance(data, dict) else {"value": data},
|
|
2577
2642
|
)
|
|
2578
2643
|
return {
|
|
2579
2644
|
"status": "success",
|
|
2580
2645
|
"error_code": None,
|
|
2581
2646
|
"recoverable": False,
|
|
2582
|
-
"message": "read chart detail",
|
|
2583
|
-
"normalized_args": {
|
|
2584
|
-
"chart_id": chart_id,
|
|
2585
|
-
"data_payload": normalized_payload,
|
|
2586
|
-
"page_num": page_num,
|
|
2587
|
-
"page_size": page_size,
|
|
2588
|
-
"page_num_y": page_num_y,
|
|
2589
|
-
"page_size_y": page_size_y,
|
|
2590
|
-
},
|
|
2647
|
+
"message": "read chart config detail",
|
|
2648
|
+
"normalized_args": {"chart_id": chart_id},
|
|
2591
2649
|
"missing_fields": [],
|
|
2592
2650
|
"allowed_values": {},
|
|
2593
2651
|
"details": {},
|
|
@@ -2699,7 +2757,7 @@ class AiBuilderFacade:
|
|
|
2699
2757
|
},
|
|
2700
2758
|
details={"unknown_selectors": missing_selectors},
|
|
2701
2759
|
missing_fields=[str(item) for item in missing_selectors],
|
|
2702
|
-
suggested_next_call={"tool_name": "
|
|
2760
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": request.app_key}},
|
|
2703
2761
|
)
|
|
2704
2762
|
merged = _merge_layout(
|
|
2705
2763
|
current_layout={
|
|
@@ -2799,7 +2857,7 @@ class AiBuilderFacade:
|
|
|
2799
2857
|
elif first_issue.get("kind", "").startswith("member"):
|
|
2800
2858
|
suggested_call = {"tool_name": "member_search", "arguments": {"profile": profile, "query": first_issue.get("value") or ""}}
|
|
2801
2859
|
elif first_issue.get("kind") in {"editable_fields", "condition_fields"}:
|
|
2802
|
-
suggested_call = {"tool_name": "
|
|
2860
|
+
suggested_call = {"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": request.app_key}}
|
|
2803
2861
|
return _failed(
|
|
2804
2862
|
first_issue.get("error_code") or "FLOW_ASSIGNEE_UNRESOLVED",
|
|
2805
2863
|
"workflow contains unresolved assignees or field permissions",
|
|
@@ -3187,7 +3245,7 @@ class AiBuilderFacade:
|
|
|
3187
3245
|
normalized_args=normalized_args,
|
|
3188
3246
|
allowed_values={"field_types": [item.value for item in PublicFieldType]},
|
|
3189
3247
|
details=_with_state_read_blocked_details({"app_key": target.app_key}, resource="schema", error=api_error),
|
|
3190
|
-
suggested_next_call={"tool_name": "
|
|
3248
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": target.app_key}},
|
|
3191
3249
|
))
|
|
3192
3250
|
schema_result = _empty_schema_result(target.app_name)
|
|
3193
3251
|
_schema_source = "synthetic_new_app"
|
|
@@ -3212,7 +3270,7 @@ class AiBuilderFacade:
|
|
|
3212
3270
|
f"field '{patch.name}' already exists",
|
|
3213
3271
|
normalized_args=normalized_args,
|
|
3214
3272
|
details={"field_name": patch.name},
|
|
3215
|
-
suggested_next_call={"tool_name": "
|
|
3273
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": target.app_key}},
|
|
3216
3274
|
)
|
|
3217
3275
|
current_fields.append(field_dict)
|
|
3218
3276
|
existing_index[field_dict["field_id"]] = len(current_fields) - 1
|
|
@@ -3228,7 +3286,7 @@ class AiBuilderFacade:
|
|
|
3228
3286
|
"field selector did not match any existing field",
|
|
3229
3287
|
normalized_args=normalized_args,
|
|
3230
3288
|
details={"selector": patch.selector.model_dump(mode="json")},
|
|
3231
|
-
suggested_next_call={"tool_name": "
|
|
3289
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": target.app_key}},
|
|
3232
3290
|
)
|
|
3233
3291
|
field = current_fields[matched]
|
|
3234
3292
|
previous_name = field["name"]
|
|
@@ -3246,7 +3304,7 @@ class AiBuilderFacade:
|
|
|
3246
3304
|
"remove selector did not match any existing field",
|
|
3247
3305
|
normalized_args=normalized_args,
|
|
3248
3306
|
details={"selector": patch.model_dump(mode="json")},
|
|
3249
|
-
suggested_next_call={"tool_name": "
|
|
3307
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": target.app_key}},
|
|
3250
3308
|
)
|
|
3251
3309
|
field = current_fields.pop(matched)
|
|
3252
3310
|
layout = _remove_field_from_layout(layout, field["name"])
|
|
@@ -3269,7 +3327,7 @@ class AiBuilderFacade:
|
|
|
3269
3327
|
api_error,
|
|
3270
3328
|
normalized_args=normalized_args,
|
|
3271
3329
|
details={"app_key": target.app_key},
|
|
3272
|
-
suggested_next_call={"tool_name": "
|
|
3330
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": target.app_key}},
|
|
3273
3331
|
)
|
|
3274
3332
|
except ValueError as error:
|
|
3275
3333
|
return _failed(
|
|
@@ -3277,7 +3335,7 @@ class AiBuilderFacade:
|
|
|
3277
3335
|
str(error),
|
|
3278
3336
|
normalized_args=normalized_args,
|
|
3279
3337
|
details={"app_key": target.app_key},
|
|
3280
|
-
suggested_next_call={"tool_name": "
|
|
3338
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": target.app_key}},
|
|
3281
3339
|
)
|
|
3282
3340
|
|
|
3283
3341
|
try:
|
|
@@ -3291,7 +3349,7 @@ class AiBuilderFacade:
|
|
|
3291
3349
|
str(error),
|
|
3292
3350
|
normalized_args=normalized_args,
|
|
3293
3351
|
details={"app_key": target.app_key},
|
|
3294
|
-
suggested_next_call={"tool_name": "
|
|
3352
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": target.app_key}},
|
|
3295
3353
|
)
|
|
3296
3354
|
|
|
3297
3355
|
q_linker_schema_context = deepcopy(schema_result)
|
|
@@ -3307,7 +3365,7 @@ class AiBuilderFacade:
|
|
|
3307
3365
|
str(error),
|
|
3308
3366
|
normalized_args=normalized_args,
|
|
3309
3367
|
details={"app_key": target.app_key},
|
|
3310
|
-
suggested_next_call={"tool_name": "
|
|
3368
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": target.app_key}},
|
|
3311
3369
|
)
|
|
3312
3370
|
|
|
3313
3371
|
relation_field_count = _count_relation_fields(current_fields)
|
|
@@ -3386,7 +3444,7 @@ class AiBuilderFacade:
|
|
|
3386
3444
|
request_id=api_error.request_id,
|
|
3387
3445
|
backend_code=api_error.backend_code,
|
|
3388
3446
|
http_status=None if api_error.http_status == 404 else api_error.http_status,
|
|
3389
|
-
suggested_next_call={"tool_name": "
|
|
3447
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": target.app_key}},
|
|
3390
3448
|
)
|
|
3391
3449
|
return _failed_from_api_error(
|
|
3392
3450
|
"SCHEMA_APPLY_FAILED",
|
|
@@ -3397,7 +3455,7 @@ class AiBuilderFacade:
|
|
|
3397
3455
|
"app_key": target.app_key,
|
|
3398
3456
|
"field_diff": {"added": added, "updated": updated, "removed": removed},
|
|
3399
3457
|
},
|
|
3400
|
-
suggested_next_call={"tool_name": "
|
|
3458
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": target.app_key}},
|
|
3401
3459
|
)
|
|
3402
3460
|
if _code_block_relations_need_source_rebind(compiled_question_relations) or _q_linker_relations_need_source_rebind(compiled_question_relations):
|
|
3403
3461
|
try:
|
|
@@ -3431,7 +3489,7 @@ class AiBuilderFacade:
|
|
|
3431
3489
|
str(error),
|
|
3432
3490
|
normalized_args=normalized_args,
|
|
3433
3491
|
details={"app_key": target.app_key},
|
|
3434
|
-
suggested_next_call={"tool_name": "
|
|
3492
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": target.app_key}},
|
|
3435
3493
|
)
|
|
3436
3494
|
except (QingflowApiError, RuntimeError) as error:
|
|
3437
3495
|
api_error = _coerce_api_error(error)
|
|
@@ -3444,7 +3502,7 @@ class AiBuilderFacade:
|
|
|
3444
3502
|
"app_key": target.app_key,
|
|
3445
3503
|
"field_diff": {"added": added, "updated": updated, "removed": removed},
|
|
3446
3504
|
},
|
|
3447
|
-
suggested_next_call={"tool_name": "
|
|
3505
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": target.app_key}},
|
|
3448
3506
|
)
|
|
3449
3507
|
rebound_payload = _build_form_payload_from_fields(
|
|
3450
3508
|
title=rebound_schema.get("formTitle") or target.app_name,
|
|
@@ -3471,7 +3529,7 @@ class AiBuilderFacade:
|
|
|
3471
3529
|
"app_key": target.app_key,
|
|
3472
3530
|
"field_diff": {"added": added, "updated": updated, "removed": removed},
|
|
3473
3531
|
},
|
|
3474
|
-
suggested_next_call={"tool_name": "
|
|
3532
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": target.app_key}},
|
|
3475
3533
|
)
|
|
3476
3534
|
current_fields = rebound_fields
|
|
3477
3535
|
response = {
|
|
@@ -3623,7 +3681,7 @@ class AiBuilderFacade:
|
|
|
3623
3681
|
api_error,
|
|
3624
3682
|
normalized_args=normalized_args,
|
|
3625
3683
|
details=_with_state_read_blocked_details({"app_key": app_key}, resource="schema", error=api_error),
|
|
3626
|
-
suggested_next_call={"tool_name": "
|
|
3684
|
+
suggested_next_call={"tool_name": "app_get_layout", "arguments": {"profile": profile, "app_key": app_key}},
|
|
3627
3685
|
))
|
|
3628
3686
|
parsed = _parse_schema(schema_result)
|
|
3629
3687
|
current_fields = parsed["fields"]
|
|
@@ -3636,7 +3694,7 @@ class AiBuilderFacade:
|
|
|
3636
3694
|
normalized_args=normalized_args,
|
|
3637
3695
|
details={"unknown_selectors": missing_selectors},
|
|
3638
3696
|
missing_fields=[str(item) for item in missing_selectors],
|
|
3639
|
-
suggested_next_call={"tool_name": "
|
|
3697
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": app_key}},
|
|
3640
3698
|
)
|
|
3641
3699
|
fields_by_name = {field["name"]: field for field in current_fields}
|
|
3642
3700
|
seen: list[str] = []
|
|
@@ -3649,7 +3707,7 @@ class AiBuilderFacade:
|
|
|
3649
3707
|
f"layout references unknown field '{field_name}'",
|
|
3650
3708
|
normalized_args=normalized_args,
|
|
3651
3709
|
details={"field_name": field_name},
|
|
3652
|
-
suggested_next_call={"tool_name": "
|
|
3710
|
+
suggested_next_call={"tool_name": "app_get_layout", "arguments": {"profile": profile, "app_key": app_key}},
|
|
3653
3711
|
)
|
|
3654
3712
|
if field_name in seen:
|
|
3655
3713
|
return _failed(
|
|
@@ -3790,7 +3848,7 @@ class AiBuilderFacade:
|
|
|
3790
3848
|
"allowed_values": {"modes": ["merge", "replace"]},
|
|
3791
3849
|
"details": {},
|
|
3792
3850
|
"request_id": None,
|
|
3793
|
-
"suggested_next_call": {"tool_name": "
|
|
3851
|
+
"suggested_next_call": {"tool_name": "app_get_layout", "arguments": {"profile": profile, "app_key": app_key}},
|
|
3794
3852
|
"noop": False,
|
|
3795
3853
|
"warnings": [],
|
|
3796
3854
|
"verification": {"layout_verified": False, "layout_summary_verified": False, "layout_read_unavailable": True},
|
|
@@ -3911,7 +3969,7 @@ class AiBuilderFacade:
|
|
|
3911
3969
|
api_error,
|
|
3912
3970
|
normalized_args=normalized_args,
|
|
3913
3971
|
details=_with_state_read_blocked_details({"app_key": app_key}, resource="workflow", error=api_error),
|
|
3914
|
-
suggested_next_call={"tool_name": "
|
|
3972
|
+
suggested_next_call={"tool_name": "app_get_flow", "arguments": {"profile": profile, "app_key": app_key}},
|
|
3915
3973
|
))
|
|
3916
3974
|
entity = _entity_spec_from_app(base_info=base, schema=schema, views=None)
|
|
3917
3975
|
current_fields = _parse_schema(schema)["fields"]
|
|
@@ -3939,7 +3997,7 @@ class AiBuilderFacade:
|
|
|
3939
3997
|
elif first_issue.get("kind", "").startswith("member"):
|
|
3940
3998
|
suggested_call = {"tool_name": "member_search", "arguments": {"profile": profile, "query": first_issue.get("value") or ""}}
|
|
3941
3999
|
elif first_issue.get("kind") in {"editable_fields", "condition_fields"}:
|
|
3942
|
-
suggested_call = {"tool_name": "
|
|
4000
|
+
suggested_call = {"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": app_key}}
|
|
3943
4001
|
return _failed(
|
|
3944
4002
|
first_issue.get("error_code") or "FLOW_ASSIGNEE_UNRESOLVED",
|
|
3945
4003
|
"workflow contains unresolved assignees or field permissions",
|
|
@@ -4041,7 +4099,7 @@ class AiBuilderFacade:
|
|
|
4041
4099
|
error_code = "FLOW_READBACK_PENDING"
|
|
4042
4100
|
recoverable = True
|
|
4043
4101
|
message = "applied workflow patch; flow readback pending"
|
|
4044
|
-
suggested_next_call = {"tool_name": "
|
|
4102
|
+
suggested_next_call = {"tool_name": "app_get_flow", "arguments": {"profile": profile, "app_key": app_key}}
|
|
4045
4103
|
elif workflow_verified:
|
|
4046
4104
|
status = "success"
|
|
4047
4105
|
error_code = None
|
|
@@ -4057,7 +4115,7 @@ class AiBuilderFacade:
|
|
|
4057
4115
|
if workflow_structure_verified and not branch_structure_verified
|
|
4058
4116
|
else "applied workflow patch; flow readback did not confirm the requested workflow"
|
|
4059
4117
|
)
|
|
4060
|
-
suggested_next_call = {"tool_name": "
|
|
4118
|
+
suggested_next_call = {"tool_name": "app_get_flow", "arguments": {"profile": profile, "app_key": app_key}}
|
|
4061
4119
|
if not branch_structure_verified:
|
|
4062
4120
|
warnings.append(_warning("WORKFLOW_BRANCH_STRUCTURE_UNVERIFIED", "branch or condition structure was written, but MCP could not fully verify downstream lane structure"))
|
|
4063
4121
|
response = {
|
|
@@ -4145,7 +4203,7 @@ class AiBuilderFacade:
|
|
|
4145
4203
|
api_error,
|
|
4146
4204
|
normalized_args=normalized_args,
|
|
4147
4205
|
details=_with_state_read_blocked_details({"app_key": app_key}, resource="views", error=api_error),
|
|
4148
|
-
suggested_next_call={"tool_name": "
|
|
4206
|
+
suggested_next_call={"tool_name": "app_get_views", "arguments": {"profile": profile, "app_key": app_key}},
|
|
4149
4207
|
))
|
|
4150
4208
|
existing_views = existing_views or []
|
|
4151
4209
|
existing_by_key: dict[str, dict[str, Any]] = {}
|
|
@@ -4222,7 +4280,7 @@ class AiBuilderFacade:
|
|
|
4222
4280
|
if len(matches) > 1:
|
|
4223
4281
|
return _failed(
|
|
4224
4282
|
"AMBIGUOUS_VIEW",
|
|
4225
|
-
"multiple views matched remove request; use
|
|
4283
|
+
"multiple views matched remove request; use app_get_views and resolve duplicates before removing by name",
|
|
4226
4284
|
normalized_args=normalized_args,
|
|
4227
4285
|
details={
|
|
4228
4286
|
"app_key": app_key,
|
|
@@ -4232,7 +4290,7 @@ class AiBuilderFacade:
|
|
|
4232
4290
|
for view in matches
|
|
4233
4291
|
],
|
|
4234
4292
|
},
|
|
4235
|
-
suggested_next_call={"tool_name": "
|
|
4293
|
+
suggested_next_call={"tool_name": "app_get_views", "arguments": {"profile": profile, "app_key": app_key}},
|
|
4236
4294
|
)
|
|
4237
4295
|
if len(matches) == 1:
|
|
4238
4296
|
key = _extract_view_key(matches[0])
|
|
@@ -4281,7 +4339,7 @@ class AiBuilderFacade:
|
|
|
4281
4339
|
"ignored_system_columns": ignored_system_columns,
|
|
4282
4340
|
},
|
|
4283
4341
|
missing_fields=missing_columns,
|
|
4284
|
-
suggested_next_call={"tool_name": "
|
|
4342
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": app_key}},
|
|
4285
4343
|
)
|
|
4286
4344
|
if patch.group_by and patch.group_by not in field_names:
|
|
4287
4345
|
return _failed(
|
|
@@ -4294,7 +4352,7 @@ class AiBuilderFacade:
|
|
|
4294
4352
|
"missing_fields": [patch.group_by],
|
|
4295
4353
|
},
|
|
4296
4354
|
missing_fields=[patch.group_by],
|
|
4297
|
-
suggested_next_call={"tool_name": "
|
|
4355
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": app_key}},
|
|
4298
4356
|
)
|
|
4299
4357
|
for gantt_field_name in (patch.start_field, patch.end_field, patch.title_field):
|
|
4300
4358
|
if gantt_field_name and gantt_field_name not in field_names:
|
|
@@ -4308,7 +4366,7 @@ class AiBuilderFacade:
|
|
|
4308
4366
|
"missing_fields": [gantt_field_name],
|
|
4309
4367
|
},
|
|
4310
4368
|
missing_fields=[gantt_field_name],
|
|
4311
|
-
suggested_next_call={"tool_name": "
|
|
4369
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": app_key}},
|
|
4312
4370
|
)
|
|
4313
4371
|
translated_filters, filter_issues = _build_view_filter_groups(current_fields_by_name=current_fields_by_name, filters=patch.filters)
|
|
4314
4372
|
if filter_issues:
|
|
@@ -4324,7 +4382,7 @@ class AiBuilderFacade:
|
|
|
4324
4382
|
},
|
|
4325
4383
|
missing_fields=list(first_issue.get("missing_fields") or []),
|
|
4326
4384
|
allowed_values=first_issue.get("allowed_values") or {"view_types": [member.value for member in PublicViewType], "view.filter.operator": [member.value for member in ViewFilterOperator]},
|
|
4327
|
-
suggested_next_call={"tool_name": "
|
|
4385
|
+
suggested_next_call={"tool_name": "app_get_fields", "arguments": {"profile": profile, "app_key": app_key}},
|
|
4328
4386
|
)
|
|
4329
4387
|
explicit_button_dtos: list[dict[str, Any]] | None = None
|
|
4330
4388
|
expected_button_summary: list[dict[str, Any]] | None = None
|
|
@@ -4363,7 +4421,7 @@ class AiBuilderFacade:
|
|
|
4363
4421
|
f"view_key '{patch.view_key}' does not exist on this app",
|
|
4364
4422
|
normalized_args=normalized_args,
|
|
4365
4423
|
details={"app_key": app_key, "view_key": patch.view_key, "view_name": patch.name},
|
|
4366
|
-
suggested_next_call={"tool_name": "
|
|
4424
|
+
suggested_next_call={"tool_name": "app_get_views", "arguments": {"profile": profile, "app_key": app_key}},
|
|
4367
4425
|
)
|
|
4368
4426
|
existing_key = patch.view_key
|
|
4369
4427
|
else:
|
|
@@ -4381,7 +4439,7 @@ class AiBuilderFacade:
|
|
|
4381
4439
|
for view in name_matches
|
|
4382
4440
|
],
|
|
4383
4441
|
},
|
|
4384
|
-
suggested_next_call={"tool_name": "
|
|
4442
|
+
suggested_next_call={"tool_name": "app_get_views", "arguments": {"profile": profile, "app_key": app_key}},
|
|
4385
4443
|
)
|
|
4386
4444
|
if len(name_matches) == 1:
|
|
4387
4445
|
matched_existing_view = name_matches[0]
|
|
@@ -4673,7 +4731,7 @@ class AiBuilderFacade:
|
|
|
4673
4731
|
api_error,
|
|
4674
4732
|
normalized_args=normalized_args,
|
|
4675
4733
|
details=_with_state_read_blocked_details({"app_key": app_key}, resource="views", error=api_error),
|
|
4676
|
-
suggested_next_call={"tool_name": "
|
|
4734
|
+
suggested_next_call={"tool_name": "app_get_views", "arguments": {"profile": profile, "app_key": app_key}},
|
|
4677
4735
|
))
|
|
4678
4736
|
verified_names = {
|
|
4679
4737
|
_extract_view_name(item)
|
|
@@ -4893,7 +4951,7 @@ class AiBuilderFacade:
|
|
|
4893
4951
|
),
|
|
4894
4952
|
},
|
|
4895
4953
|
"request_id": first_failure.get("request_id"),
|
|
4896
|
-
"suggested_next_call": {"tool_name": "
|
|
4954
|
+
"suggested_next_call": {"tool_name": "app_get_views", "arguments": {"profile": profile, "app_key": app_key}},
|
|
4897
4955
|
"backend_code": first_failure.get("backend_code"),
|
|
4898
4956
|
"http_status": first_failure.get("http_status"),
|
|
4899
4957
|
"noop": noop,
|
|
@@ -4966,7 +5024,7 @@ class AiBuilderFacade:
|
|
|
4966
5024
|
),
|
|
4967
5025
|
},
|
|
4968
5026
|
"request_id": None,
|
|
4969
|
-
"suggested_next_call": None if verified and view_filters_verified and view_buttons_verified else {"tool_name": "
|
|
5027
|
+
"suggested_next_call": None if verified and view_filters_verified and view_buttons_verified else {"tool_name": "app_get_views", "arguments": {"profile": profile, "app_key": app_key}},
|
|
4970
5028
|
"noop": noop,
|
|
4971
5029
|
"warnings": warnings,
|
|
4972
5030
|
"verification": {
|
|
@@ -5003,7 +5061,7 @@ class AiBuilderFacade:
|
|
|
5003
5061
|
api_error,
|
|
5004
5062
|
normalized_args=normalized_args,
|
|
5005
5063
|
details={"app_key": app_key},
|
|
5006
|
-
suggested_next_call={"tool_name": "
|
|
5064
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
5007
5065
|
)
|
|
5008
5066
|
tag_ids_before = _coerce_int_list(base_before.get("tagIds"))
|
|
5009
5067
|
already_published = bool(base_before.get("appPublishStatus") in {1, 2})
|
|
@@ -5017,7 +5075,7 @@ class AiBuilderFacade:
|
|
|
5017
5075
|
api_error,
|
|
5018
5076
|
normalized_args=normalized_args,
|
|
5019
5077
|
details={"app_key": app_key},
|
|
5020
|
-
suggested_next_call={"tool_name": "
|
|
5078
|
+
suggested_next_call={"tool_name": "app_get_views", "arguments": {"profile": profile, "app_key": app_key}},
|
|
5021
5079
|
)
|
|
5022
5080
|
views_before = views_before or []
|
|
5023
5081
|
if already_published and package_already_attached is not False and isinstance(views_before, list) and not views_before_unavailable:
|
|
@@ -5054,7 +5112,7 @@ class AiBuilderFacade:
|
|
|
5054
5112
|
api_error,
|
|
5055
5113
|
normalized_args=normalized_args,
|
|
5056
5114
|
details={"app_key": app_key, "edit_version_no": edit_version_no},
|
|
5057
|
-
suggested_next_call={"tool_name": "
|
|
5115
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
5058
5116
|
)
|
|
5059
5117
|
try:
|
|
5060
5118
|
base = self.apps.app_get_base(profile=profile, app_key=app_key, include_raw=True).get("result") or {}
|
|
@@ -5065,7 +5123,7 @@ class AiBuilderFacade:
|
|
|
5065
5123
|
api_error,
|
|
5066
5124
|
normalized_args=normalized_args,
|
|
5067
5125
|
details={"app_key": app_key},
|
|
5068
|
-
suggested_next_call={"tool_name": "
|
|
5126
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
5069
5127
|
)
|
|
5070
5128
|
tag_ids_after = _coerce_int_list(base.get("tagIds"))
|
|
5071
5129
|
package_attached = None if not expected_package_tag_id else expected_package_tag_id in tag_ids_after
|
|
@@ -5078,7 +5136,7 @@ class AiBuilderFacade:
|
|
|
5078
5136
|
api_error,
|
|
5079
5137
|
normalized_args=normalized_args,
|
|
5080
5138
|
details={"app_key": app_key},
|
|
5081
|
-
suggested_next_call={"tool_name": "
|
|
5139
|
+
suggested_next_call={"tool_name": "app_get_views", "arguments": {"profile": profile, "app_key": app_key}},
|
|
5082
5140
|
)
|
|
5083
5141
|
views = views or []
|
|
5084
5142
|
views_ok = isinstance(views, list) and not views_unavailable
|
|
@@ -5741,7 +5799,7 @@ class AiBuilderFacade:
|
|
|
5741
5799
|
api_error,
|
|
5742
5800
|
normalized_args=normalized_args,
|
|
5743
5801
|
details={"app_key": app_key, "phase": "prepare_edit_context"},
|
|
5744
|
-
suggested_next_call={"tool_name": "
|
|
5802
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
5745
5803
|
)
|
|
5746
5804
|
edit_version_no = _coerce_positive_int(version_result.get("editVersionNo") or version_result.get("versionNo")) or 1
|
|
5747
5805
|
return edit_version_no, None
|
|
@@ -6022,7 +6080,7 @@ class AiBuilderFacade:
|
|
|
6022
6080
|
"APP_CREATE_READBACK_FAILED",
|
|
6023
6081
|
api_error,
|
|
6024
6082
|
details={"app_key": new_app_key, "app_name": app_name, "package_tag_id": package_tag_id},
|
|
6025
|
-
suggested_next_call={"tool_name": "
|
|
6083
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": new_app_key}},
|
|
6026
6084
|
)
|
|
6027
6085
|
return {
|
|
6028
6086
|
"status": "success",
|
|
@@ -6095,7 +6153,7 @@ class AiBuilderFacade:
|
|
|
6095
6153
|
api_error,
|
|
6096
6154
|
normalized_args=normalized_args,
|
|
6097
6155
|
details={"app_key": app_key},
|
|
6098
|
-
suggested_next_call={"tool_name": "
|
|
6156
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
6099
6157
|
)
|
|
6100
6158
|
raw_base = base_result.get("result") if isinstance(base_result.get("result"), dict) else {}
|
|
6101
6159
|
effective_title = str(raw_base.get("formTitle") or fallback_title or "未命名应用").strip() or "未命名应用"
|
|
@@ -6121,7 +6179,7 @@ class AiBuilderFacade:
|
|
|
6121
6179
|
"app base info did not include editable auth payload required for icon update",
|
|
6122
6180
|
normalized_args=normalized_args,
|
|
6123
6181
|
details={"app_key": app_key},
|
|
6124
|
-
suggested_next_call={"tool_name": "
|
|
6182
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
6125
6183
|
)
|
|
6126
6184
|
try:
|
|
6127
6185
|
update_result = self.apps.app_update_base(profile=profile, app_key=app_key, payload=payload)
|
|
@@ -6132,7 +6190,7 @@ class AiBuilderFacade:
|
|
|
6132
6190
|
api_error,
|
|
6133
6191
|
normalized_args=normalized_args,
|
|
6134
6192
|
details={"app_key": app_key, "app_icon": desired_icon},
|
|
6135
|
-
suggested_next_call={"tool_name": "
|
|
6193
|
+
suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
6136
6194
|
)
|
|
6137
6195
|
return {
|
|
6138
6196
|
"status": "success",
|
|
@@ -8110,11 +8168,15 @@ def _parse_schema(schema: dict[str, Any]) -> dict[str, Any]:
|
|
|
8110
8168
|
section_rows.append(labels)
|
|
8111
8169
|
if section_rows:
|
|
8112
8170
|
parsed_section_id = _coerce_positive_int(section_question.get("queId"))
|
|
8171
|
+
raw_section_id = None
|
|
8113
8172
|
if parsed_section_id is None:
|
|
8114
|
-
|
|
8173
|
+
raw_section_id = str(section_question.get("sectionId") or "").strip() or None
|
|
8174
|
+
if raw_section_id is None:
|
|
8175
|
+
parsed_section_id = _coerce_positive_int(section_question.get("sectionId"))
|
|
8115
8176
|
sections.append(
|
|
8116
8177
|
{
|
|
8117
|
-
"section_id":
|
|
8178
|
+
"section_id": raw_section_id
|
|
8179
|
+
or str(parsed_section_id or _slugify(section_question.get("queTitle") or "section", default="section")),
|
|
8118
8180
|
"title": section_question.get("queTitle") or "未命名分组",
|
|
8119
8181
|
"rows": section_rows,
|
|
8120
8182
|
}
|