@josephyan/qingflow-cli 0.2.0-beta.82 → 0.2.0-beta.83

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.
@@ -71,48 +71,36 @@ class AiBuilderTools(ToolBase):
71
71
  )
72
72
 
73
73
  def register(self, mcp) -> None:
74
- @mcp.tool()
75
- def package_list(profile: str = DEFAULT_PROFILE, trial_status: str = "all") -> JSONObject:
76
- return self.package_list(profile=profile, trial_status=trial_status)
77
-
78
- @mcp.tool()
79
- def package_resolve(profile: str = DEFAULT_PROFILE, package_name: str = "") -> JSONObject:
80
- return self.package_resolve(profile=profile, package_name=package_name)
81
-
82
74
  @mcp.tool()
83
75
  def builder_tool_contract(tool_name: str = "") -> JSONObject:
84
76
  return self.builder_tool_contract(tool_name=tool_name)
85
77
 
86
78
  @mcp.tool()
87
- def package_create(
88
- profile: str = DEFAULT_PROFILE,
89
- package_name: str = "",
90
- icon: str | None = None,
91
- color: str | None = None,
92
- visibility: JSONObject | None = None,
93
- ) -> JSONObject:
94
- return self.package_create(profile=profile, package_name=package_name, icon=icon, color=color, visibility=visibility)
79
+ def package_get(profile: str = DEFAULT_PROFILE, package_id: int = 0) -> JSONObject:
80
+ return self.package_get(profile=profile, package_id=package_id)
95
81
 
96
82
  @mcp.tool()
97
- def package_get(profile: str = DEFAULT_PROFILE, tag_id: int = 0) -> JSONObject:
98
- return self.package_get(profile=profile, tag_id=tag_id)
99
-
100
- @mcp.tool()
101
- def package_update(
83
+ def package_apply(
102
84
  profile: str = DEFAULT_PROFILE,
103
- tag_id: int = 0,
85
+ package_id: int | None = None,
104
86
  package_name: str | None = None,
87
+ create_if_missing: bool = False,
105
88
  icon: str | None = None,
106
89
  color: str | None = None,
107
90
  visibility: JSONObject | None = None,
91
+ items: list[dict] | None = None,
92
+ allow_detach: bool = False,
108
93
  ) -> JSONObject:
109
- return self.package_update(
94
+ return self.package_apply(
110
95
  profile=profile,
111
- tag_id=tag_id,
96
+ package_id=package_id,
112
97
  package_name=package_name,
98
+ create_if_missing=create_if_missing,
113
99
  icon=icon,
114
100
  color=color,
115
101
  visibility=visibility,
102
+ items=items or None,
103
+ allow_detach=allow_detach,
116
104
  )
117
105
 
118
106
  @mcp.tool()
@@ -172,14 +160,6 @@ class AiBuilderTools(ToolBase):
172
160
  role_icon=role_icon,
173
161
  )
174
162
 
175
- @mcp.tool()
176
- def package_attach_app(
177
- profile: str = DEFAULT_PROFILE,
178
- tag_id: int = 0,
179
- app_key: str = "",
180
- ) -> JSONObject:
181
- return self.package_attach_app(profile=profile, tag_id=tag_id, app_key=app_key)
182
-
183
163
  @mcp.tool()
184
164
  def app_release_edit_lock_if_mine(
185
165
  profile: str = DEFAULT_PROFILE,
@@ -199,24 +179,24 @@ class AiBuilderTools(ToolBase):
199
179
  profile: str = DEFAULT_PROFILE,
200
180
  app_key: str = "",
201
181
  app_name: str = "",
202
- package_tag_id: int | None = None,
182
+ package_id: int | None = None,
203
183
  ) -> JSONObject:
204
184
  has_app_key = bool((app_key or "").strip())
205
185
  has_app_name = bool((app_name or "").strip())
206
- has_package_tag_id = package_tag_id is not None
207
- if has_app_key and (has_app_name or has_package_tag_id):
186
+ has_package_id = package_id is not None
187
+ if has_app_key and (has_app_name or has_package_id):
208
188
  return _config_failure(
209
189
  tool_name="app_resolve",
210
190
  message="app_resolve accepts exactly one selector mode.",
211
- fix_hint="Use only `app_key`, or use `app_name` together with `package_tag_id`.",
191
+ fix_hint="Use only `app_key`, or use `app_name` together with `package_id`.",
212
192
  )
213
- if not has_app_key and not (has_app_name and has_package_tag_id):
193
+ if not has_app_key and not (has_app_name and has_package_id):
214
194
  return _config_failure(
215
195
  tool_name="app_resolve",
216
- message="app_resolve requires either app_key, or app_name together with package_tag_id.",
217
- fix_hint="For an existing known app, pass `app_key`. For package-scoped lookup, pass both `app_name` and `package_tag_id`.",
196
+ message="app_resolve requires either app_key, or app_name together with package_id.",
197
+ fix_hint="For an existing known app, pass `app_key`. For package-scoped lookup, pass both `app_name` and `package_id`.",
218
198
  )
219
- return self.app_resolve(profile=profile, app_key=app_key, app_name=app_name, package_tag_id=package_tag_id)
199
+ return self.app_resolve(profile=profile, app_key=app_key, app_name=app_name, package_id=package_id)
220
200
 
221
201
  @mcp.tool()
222
202
  def app_custom_button_list(profile: str = DEFAULT_PROFILE, app_key: str = "") -> JSONObject:
@@ -307,7 +287,7 @@ class AiBuilderTools(ToolBase):
307
287
  def app_schema_apply(
308
288
  profile: str = DEFAULT_PROFILE,
309
289
  app_key: str = "",
310
- package_tag_id: int | None = None,
290
+ package_id: int | None = None,
311
291
  app_name: str = "",
312
292
  app_title: str = "",
313
293
  icon: str = "",
@@ -322,24 +302,24 @@ class AiBuilderTools(ToolBase):
322
302
  has_app_key = bool((app_key or "").strip())
323
303
  has_app_name = bool((app_name or "").strip())
324
304
  has_app_title = bool((app_title or "").strip())
325
- has_package_tag_id = package_tag_id is not None
305
+ has_package_id = package_id is not None
326
306
  if has_app_key:
327
- if create_if_missing or has_package_tag_id:
307
+ if create_if_missing or has_package_id:
328
308
  return _config_failure(
329
309
  tool_name="app_schema_apply",
330
310
  message="app_schema_apply edit mode accepts app_key and optional app_name rename only.",
331
- fix_hint="For existing apps, use `app_key` and optionally `app_name`. For create mode, use `package_tag_id + app_name + create_if_missing=true`.",
311
+ fix_hint="For existing apps, use `app_key` and optionally `app_name`. For create mode, use `package_id + app_name + create_if_missing=true`.",
332
312
  )
333
- elif not (create_if_missing and has_package_tag_id and (has_app_name or has_app_title)):
313
+ elif not (create_if_missing and has_package_id and (has_app_name or has_app_title)):
334
314
  return _config_failure(
335
315
  tool_name="app_schema_apply",
336
- message="app_schema_apply create mode requires package_tag_id, app_name, and create_if_missing=true.",
337
- fix_hint="Use `app_key` for existing apps, or pass `package_tag_id + app_name + create_if_missing=true` to create a new app.",
316
+ message="app_schema_apply create mode requires package_id, app_name, and create_if_missing=true.",
317
+ fix_hint="Use `app_key` for existing apps, or pass `package_id + app_name + create_if_missing=true` to create a new app.",
338
318
  )
339
319
  return self.app_schema_apply(
340
320
  profile=profile,
341
321
  app_key=app_key,
342
- package_tag_id=package_tag_id,
322
+ package_id=package_id,
343
323
  app_name=app_name,
344
324
  app_title=app_title,
345
325
  icon=icon,
@@ -417,7 +397,7 @@ class AiBuilderTools(ToolBase):
417
397
  profile: str = DEFAULT_PROFILE,
418
398
  dash_key: str = "",
419
399
  dash_name: str = "",
420
- package_tag_id: int | None = None,
400
+ package_id: int | None = None,
421
401
  publish: bool = True,
422
402
  sections: list[JSONObject] | None = None,
423
403
  visibility: JSONObject | None = None,
@@ -430,24 +410,24 @@ class AiBuilderTools(ToolBase):
430
410
  ) -> JSONObject:
431
411
  has_dash_key = bool((dash_key or "").strip())
432
412
  has_dash_name = bool((dash_name or "").strip())
433
- has_package_tag_id = package_tag_id is not None
434
- if has_dash_key and has_package_tag_id:
413
+ has_package_id = package_id is not None
414
+ if has_dash_key and has_package_id:
435
415
  return _config_failure(
436
416
  tool_name="portal_apply",
437
417
  message="portal_apply accepts exactly one selector mode.",
438
- fix_hint="Use `dash_key` to update an existing portal, or use `package_tag_id + dash_name` to create a new portal.",
418
+ fix_hint="Use `dash_key` to update an existing portal, or use `package_id + dash_name` to create a new portal.",
439
419
  )
440
- if not has_dash_key and not (has_package_tag_id and has_dash_name):
420
+ if not has_dash_key and not (has_package_id and has_dash_name):
441
421
  return _config_failure(
442
422
  tool_name="portal_apply",
443
- message="portal_apply requires either dash_key, or package_tag_id together with dash_name.",
444
- fix_hint="Use `dash_key` for an existing portal. For create mode, pass `package_tag_id + dash_name`.",
423
+ message="portal_apply requires either dash_key, or package_id together with dash_name.",
424
+ fix_hint="Use `dash_key` for an existing portal. For create mode, pass `package_id + dash_name`.",
445
425
  )
446
426
  return self.portal_apply(
447
427
  profile=profile,
448
428
  dash_key=dash_key,
449
429
  dash_name=dash_name,
450
- package_tag_id=package_tag_id,
430
+ package_id=package_id,
451
431
  publish=publish,
452
432
  sections=sections or [],
453
433
  visibility=visibility,
@@ -463,12 +443,12 @@ class AiBuilderTools(ToolBase):
463
443
  def app_publish_verify(
464
444
  profile: str = DEFAULT_PROFILE,
465
445
  app_key: str = "",
466
- expected_package_tag_id: int | None = None,
446
+ expected_package_id: int | None = None,
467
447
  ) -> JSONObject:
468
448
  return self.app_publish_verify(
469
449
  profile=profile,
470
450
  app_key=app_key,
471
- expected_package_tag_id=expected_package_tag_id,
451
+ expected_package_id=expected_package_id,
472
452
  )
473
453
 
474
454
  def package_list(self, *, profile: str, trial_status: str = "all") -> JSONObject:
@@ -494,10 +474,10 @@ class AiBuilderTools(ToolBase):
494
474
  public_tool_names = public_builder_contract_tool_names()
495
475
  if requested in _PRIVATE_BUILDER_TOOL_CONTRACTS:
496
476
  lookup_name = ""
497
- elif requested in _BUILDER_TOOL_CONTRACTS:
498
- lookup_name = requested
499
477
  else:
500
478
  lookup_name = _BUILDER_TOOL_CONTRACT_ALIASES.get(requested, requested)
479
+ if lookup_name not in public_tool_names:
480
+ lookup_name = ""
501
481
  contract = _BUILDER_TOOL_CONTRACTS.get(lookup_name)
502
482
  if contract is None:
503
483
  return {
@@ -582,14 +562,60 @@ class AiBuilderTools(ToolBase):
582
562
  },
583
563
  )
584
564
 
585
- def package_get(self, *, profile: str, tag_id: int) -> JSONObject:
586
- normalized_args = {"tag_id": tag_id}
587
- return _safe_tool_call(
588
- lambda: self._facade.package_get(profile=profile, tag_id=tag_id),
565
+ def package_get(self, *, profile: str, package_id: int | None = None) -> JSONObject:
566
+ normalized_args = {"package_id": package_id}
567
+ return _publicize_package_fields(_safe_tool_call(
568
+ lambda: self._facade.package_get(profile=profile, package_id=package_id),
589
569
  error_code="PACKAGE_GET_FAILED",
590
570
  normalized_args=normalized_args,
591
- suggested_next_call={"tool_name": "package_get", "arguments": {"profile": profile, "tag_id": tag_id}},
592
- )
571
+ suggested_next_call={"tool_name": "package_get", "arguments": {"profile": profile, "package_id": package_id}},
572
+ ))
573
+
574
+ def package_apply(
575
+ self,
576
+ *,
577
+ profile: str,
578
+ package_id: int | None = None,
579
+ package_name: str | None = None,
580
+ create_if_missing: bool = False,
581
+ icon: str | None = None,
582
+ color: str | None = None,
583
+ visibility: JSONObject | None = None,
584
+ items: list[dict] | None = None,
585
+ allow_detach: bool = False,
586
+ ) -> JSONObject:
587
+ visibility_patch = None
588
+ if visibility is not None:
589
+ try:
590
+ visibility_patch = VisibilityPatch.model_validate(visibility)
591
+ except ValidationError as exc:
592
+ return _visibility_validation_failure(str(exc), tool_name="package_apply", exc=exc)
593
+ normalized_args = {
594
+ "package_id": package_id,
595
+ **({"package_name": package_name} if str(package_name or "").strip() else {}),
596
+ "create_if_missing": bool(create_if_missing),
597
+ **({"icon": icon} if icon else {}),
598
+ **({"color": color} if color else {}),
599
+ **({"visibility": visibility_patch.model_dump(mode="json")} if visibility_patch is not None else {}),
600
+ **({"items": deepcopy(items)} if items is not None else {}),
601
+ "allow_detach": bool(allow_detach),
602
+ }
603
+ return _publicize_package_fields(_safe_tool_call(
604
+ lambda: self._facade.package_apply(
605
+ profile=profile,
606
+ package_id=package_id,
607
+ package_name=package_name,
608
+ create_if_missing=create_if_missing,
609
+ icon=icon,
610
+ color=color,
611
+ visibility=visibility_patch,
612
+ items=items,
613
+ allow_detach=allow_detach,
614
+ ),
615
+ error_code="PACKAGE_APPLY_FAILED",
616
+ normalized_args=normalized_args,
617
+ suggested_next_call={"tool_name": "package_apply", "arguments": {"profile": profile, **normalized_args}},
618
+ ))
593
619
 
594
620
  def package_update(
595
621
  self,
@@ -765,14 +791,21 @@ class AiBuilderTools(ToolBase):
765
791
  suggested_next_call={"tool_name": "app_release_edit_lock_if_mine", "arguments": {"profile": profile, **normalized_args}},
766
792
  )
767
793
 
768
- def app_resolve(self, *, profile: str, app_key: str = "", app_name: str = "", package_tag_id: int | None = None) -> JSONObject:
769
- normalized_args = {"app_key": app_key, "app_name": app_name, "package_tag_id": package_tag_id}
770
- return _safe_tool_call(
771
- lambda: self._facade.app_resolve(profile=profile, app_key=app_key, app_name=app_name, package_tag_id=package_tag_id),
794
+ def app_resolve(
795
+ self,
796
+ *,
797
+ profile: str,
798
+ app_key: str = "",
799
+ app_name: str = "",
800
+ package_id: int | None = None,
801
+ ) -> JSONObject:
802
+ normalized_args = {"app_key": app_key, "app_name": app_name, "package_id": package_id}
803
+ return _publicize_package_fields(_safe_tool_call(
804
+ lambda: self._facade.app_resolve(profile=profile, app_key=app_key, app_name=app_name, package_tag_id=package_id),
772
805
  error_code="APP_RESOLVE_FAILED",
773
806
  normalized_args=normalized_args,
774
807
  suggested_next_call={"tool_name": "app_resolve", "arguments": {"profile": profile, **normalized_args}},
775
- )
808
+ ))
776
809
 
777
810
  def app_custom_button_list(self, *, profile: str, app_key: str) -> JSONObject:
778
811
  normalized_args = {"app_key": app_key}
@@ -868,21 +901,21 @@ class AiBuilderTools(ToolBase):
868
901
 
869
902
  def app_read_summary(self, *, profile: str, app_key: str) -> JSONObject:
870
903
  normalized_args = {"app_key": app_key}
871
- return _safe_tool_call(
904
+ return _publicize_package_fields(_safe_tool_call(
872
905
  lambda: self._facade.app_read_summary(profile=profile, app_key=app_key),
873
906
  error_code="APP_READ_FAILED",
874
907
  normalized_args=normalized_args,
875
908
  suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
876
- )
909
+ ))
877
910
 
878
911
  def app_get(self, *, profile: str, app_key: str) -> JSONObject:
879
912
  normalized_args = {"app_key": app_key}
880
- return _safe_tool_call(
913
+ return _publicize_package_fields(_safe_tool_call(
881
914
  lambda: self._facade.app_get(profile=profile, app_key=app_key),
882
915
  error_code="APP_GET_FAILED",
883
916
  normalized_args=normalized_args,
884
917
  suggested_next_call={"tool_name": "app_get", "arguments": {"profile": profile, "app_key": app_key}},
885
- )
918
+ ))
886
919
 
887
920
  def app_read_fields(self, *, profile: str, app_key: str) -> JSONObject:
888
921
  normalized_args = {"app_key": app_key}
@@ -991,30 +1024,30 @@ class AiBuilderTools(ToolBase):
991
1024
  )
992
1025
 
993
1026
  def portal_list(self, *, profile: str) -> JSONObject:
994
- return _safe_tool_call(
1027
+ return _publicize_package_fields(_safe_tool_call(
995
1028
  lambda: self._facade.portal_list(profile=profile),
996
1029
  error_code="PORTAL_LIST_FAILED",
997
1030
  normalized_args={},
998
1031
  suggested_next_call={"tool_name": "portal_list", "arguments": {"profile": profile}},
999
- )
1032
+ ))
1000
1033
 
1001
1034
  def portal_get(self, *, profile: str, dash_key: str, being_draft: bool = True) -> JSONObject:
1002
1035
  normalized_args = {"dash_key": dash_key, "being_draft": being_draft}
1003
- return _safe_tool_call(
1036
+ return _publicize_package_fields(_safe_tool_call(
1004
1037
  lambda: self._facade.portal_get(profile=profile, dash_key=dash_key, being_draft=being_draft),
1005
1038
  error_code="PORTAL_GET_FAILED",
1006
1039
  normalized_args=normalized_args,
1007
1040
  suggested_next_call={"tool_name": "portal_get", "arguments": {"profile": profile, **normalized_args}},
1008
- )
1041
+ ))
1009
1042
 
1010
1043
  def portal_read_summary(self, *, profile: str, dash_key: str, being_draft: bool = True) -> JSONObject:
1011
1044
  normalized_args = {"dash_key": dash_key, "being_draft": being_draft}
1012
- return _safe_tool_call(
1045
+ return _publicize_package_fields(_safe_tool_call(
1013
1046
  lambda: self._facade.portal_read_summary(profile=profile, dash_key=dash_key, being_draft=being_draft),
1014
1047
  error_code="PORTAL_READ_FAILED",
1015
1048
  normalized_args=normalized_args,
1016
1049
  suggested_next_call={"tool_name": "portal_get", "arguments": {"profile": profile, **normalized_args}},
1017
- )
1050
+ ))
1018
1051
 
1019
1052
  def view_get(self, *, profile: str, view_key: str = "", viewgraph_key: str = "") -> JSONObject:
1020
1053
  resolved_view_key = str(view_key or viewgraph_key or "").strip()
@@ -1045,7 +1078,7 @@ class AiBuilderTools(ToolBase):
1045
1078
  *,
1046
1079
  profile: str,
1047
1080
  app_key: str = "",
1048
- package_tag_id: int | None = None,
1081
+ package_id: int | None = None,
1049
1082
  app_name: str = "",
1050
1083
  icon: str = "",
1051
1084
  color: str = "",
@@ -1059,7 +1092,7 @@ class AiBuilderTools(ToolBase):
1059
1092
  request = SchemaPlanRequest.model_validate(
1060
1093
  {
1061
1094
  "app_key": app_key,
1062
- "package_tag_id": package_tag_id,
1095
+ "package_tag_id": package_id,
1063
1096
  "app_name": app_name,
1064
1097
  "icon": icon,
1065
1098
  "color": color,
@@ -1080,7 +1113,7 @@ class AiBuilderTools(ToolBase):
1080
1113
  "arguments": {
1081
1114
  "profile": profile,
1082
1115
  "app_key": app_key,
1083
- "package_tag_id": package_tag_id,
1116
+ "package_id": package_id,
1084
1117
  "app_name": app_name,
1085
1118
  "icon": icon,
1086
1119
  "color": color,
@@ -1092,12 +1125,13 @@ class AiBuilderTools(ToolBase):
1092
1125
  },
1093
1126
  },
1094
1127
  )
1095
- return _safe_tool_call(
1128
+ normalized_args = _publicize_package_fields(request.model_dump(mode="json"))
1129
+ return _publicize_package_fields(_safe_tool_call(
1096
1130
  lambda: self._facade.app_schema_plan(profile=profile, request=request),
1097
1131
  error_code="SCHEMA_PLAN_FAILED",
1098
- normalized_args=request.model_dump(mode="json"),
1099
- suggested_next_call={"tool_name": "app_schema_plan", "arguments": {"profile": profile, **request.model_dump(mode="json")}},
1100
- )
1132
+ normalized_args=normalized_args,
1133
+ suggested_next_call={"tool_name": "app_schema_plan", "arguments": {"profile": profile, **normalized_args}},
1134
+ ))
1101
1135
 
1102
1136
  def app_layout_plan(
1103
1137
  self,
@@ -1235,7 +1269,7 @@ class AiBuilderTools(ToolBase):
1235
1269
  *,
1236
1270
  profile: str,
1237
1271
  app_key: str = "",
1238
- package_tag_id: int | None = None,
1272
+ package_id: int | None = None,
1239
1273
  app_name: str = "",
1240
1274
  app_title: str = "",
1241
1275
  icon: str = "",
@@ -1250,7 +1284,7 @@ class AiBuilderTools(ToolBase):
1250
1284
  result = self._app_schema_apply_once(
1251
1285
  profile=profile,
1252
1286
  app_key=app_key,
1253
- package_tag_id=package_tag_id,
1287
+ package_id=package_id,
1254
1288
  app_name=app_name,
1255
1289
  app_title=app_title,
1256
1290
  icon=icon,
@@ -1268,7 +1302,7 @@ class AiBuilderTools(ToolBase):
1268
1302
  retry_call=lambda: self._app_schema_apply_once(
1269
1303
  profile=profile,
1270
1304
  app_key=app_key,
1271
- package_tag_id=package_tag_id,
1305
+ package_id=package_id,
1272
1306
  app_name=app_name,
1273
1307
  app_title=app_title,
1274
1308
  icon=icon,
@@ -1287,7 +1321,7 @@ class AiBuilderTools(ToolBase):
1287
1321
  *,
1288
1322
  profile: str,
1289
1323
  app_key: str = "",
1290
- package_tag_id: int | None = None,
1324
+ package_id: int | None = None,
1291
1325
  app_name: str = "",
1292
1326
  app_title: str = "",
1293
1327
  icon: str = "",
@@ -1304,7 +1338,7 @@ class AiBuilderTools(ToolBase):
1304
1338
  result=self.app_schema_plan(
1305
1339
  profile=profile,
1306
1340
  app_key=app_key,
1307
- package_tag_id=package_tag_id,
1341
+ package_id=package_id,
1308
1342
  app_name=effective_app_name,
1309
1343
  icon=icon,
1310
1344
  color=color,
@@ -1338,7 +1372,7 @@ class AiBuilderTools(ToolBase):
1338
1372
  "arguments": {
1339
1373
  "profile": profile,
1340
1374
  "app_key": str(plan_args.get("app_key") or app_key),
1341
- "package_tag_id": plan_args.get("package_tag_id", package_tag_id),
1375
+ "package_id": plan_args.get("package_id", package_id),
1342
1376
  "app_name": str(plan_args.get("app_name") or effective_app_name),
1343
1377
  "icon": str(plan_args.get("icon") or icon),
1344
1378
  "color": str(plan_args.get("color") or color),
@@ -1353,7 +1387,7 @@ class AiBuilderTools(ToolBase):
1353
1387
  )
1354
1388
  normalized_args = {
1355
1389
  "app_key": str(plan_args.get("app_key") or app_key),
1356
- "package_tag_id": plan_args.get("package_tag_id", package_tag_id),
1390
+ "package_id": plan_args.get("package_id", package_id),
1357
1391
  "app_name": str(plan_args.get("app_name") or effective_app_name),
1358
1392
  "icon": str(plan_args.get("icon") or icon or ""),
1359
1393
  "color": str(plan_args.get("color") or color or ""),
@@ -1368,7 +1402,7 @@ class AiBuilderTools(ToolBase):
1368
1402
  lambda: self._facade.app_schema_apply(
1369
1403
  profile=profile,
1370
1404
  app_key=str(plan_args.get("app_key") or app_key),
1371
- package_tag_id=plan_args.get("package_tag_id", package_tag_id),
1405
+ package_tag_id=plan_args.get("package_id", package_id),
1372
1406
  app_name=str(plan_args.get("app_name") or effective_app_name),
1373
1407
  icon=str(plan_args.get("icon") or icon or ""),
1374
1408
  color=str(plan_args.get("color") or color or ""),
@@ -1383,7 +1417,7 @@ class AiBuilderTools(ToolBase):
1383
1417
  normalized_args=normalized_args,
1384
1418
  suggested_next_call={"tool_name": "app_schema_apply", "arguments": {"profile": profile, **normalized_args}},
1385
1419
  )
1386
- return result
1420
+ return _publicize_package_fields(result)
1387
1421
 
1388
1422
  def app_layout_apply(self, *, profile: str, app_key: str, mode: str = "merge", publish: bool = True, sections: list[JSONObject]) -> JSONObject:
1389
1423
  result = self._app_layout_apply_once(
@@ -1727,7 +1761,7 @@ class AiBuilderTools(ToolBase):
1727
1761
  profile: str,
1728
1762
  dash_key: str = "",
1729
1763
  dash_name: str = "",
1730
- package_tag_id: int | None = None,
1764
+ package_id: int | None = None,
1731
1765
  publish: bool = True,
1732
1766
  sections: list[JSONObject],
1733
1767
  visibility: JSONObject | None = None,
@@ -1743,7 +1777,7 @@ class AiBuilderTools(ToolBase):
1743
1777
  {
1744
1778
  "dash_key": dash_key or None,
1745
1779
  "dash_name": dash_name or None,
1746
- "package_tag_id": package_tag_id,
1780
+ "package_tag_id": package_id,
1747
1781
  "publish": publish,
1748
1782
  "sections": sections or [],
1749
1783
  "visibility": visibility,
@@ -1765,7 +1799,7 @@ class AiBuilderTools(ToolBase):
1765
1799
  "arguments": {
1766
1800
  "profile": profile,
1767
1801
  "dash_name": dash_name or "业务门户",
1768
- "package_tag_id": package_tag_id or 1001,
1802
+ "package_id": package_id or 1001,
1769
1803
  "publish": True,
1770
1804
  "sections": [
1771
1805
  {
@@ -1778,30 +1812,37 @@ class AiBuilderTools(ToolBase):
1778
1812
  },
1779
1813
  )
1780
1814
  normalized_args = request.model_dump(mode="json")
1781
- return _safe_tool_call(
1815
+ normalized_args["package_id"] = normalized_args.pop("package_tag_id", package_id)
1816
+ return _publicize_package_fields(_safe_tool_call(
1782
1817
  lambda: self._facade.portal_apply(profile=profile, request=request),
1783
1818
  error_code="PORTAL_APPLY_FAILED",
1784
1819
  normalized_args=normalized_args,
1785
1820
  suggested_next_call={"tool_name": "portal_apply", "arguments": {"profile": profile, **normalized_args}},
1786
- )
1821
+ ))
1787
1822
 
1788
- def app_publish_verify(self, *, profile: str, app_key: str, expected_package_tag_id: int | None = None) -> JSONObject:
1789
- normalized_args = {"app_key": app_key, "expected_package_tag_id": expected_package_tag_id}
1790
- result = _safe_tool_call(
1791
- lambda: self._facade.app_publish_verify(profile=profile, app_key=app_key, expected_package_tag_id=expected_package_tag_id),
1823
+ def app_publish_verify(
1824
+ self,
1825
+ *,
1826
+ profile: str,
1827
+ app_key: str,
1828
+ expected_package_id: int | None = None,
1829
+ ) -> JSONObject:
1830
+ normalized_args = {"app_key": app_key, "expected_package_id": expected_package_id}
1831
+ result = _publicize_package_fields(_safe_tool_call(
1832
+ lambda: self._facade.app_publish_verify(profile=profile, app_key=app_key, expected_package_tag_id=expected_package_id),
1792
1833
  error_code="PUBLISH_VERIFY_FAILED",
1793
1834
  normalized_args=normalized_args,
1794
1835
  suggested_next_call={"tool_name": "app_publish_verify", "arguments": {"profile": profile, **normalized_args}},
1795
- )
1796
- return self._retry_after_self_lock_release(
1836
+ ))
1837
+ return _publicize_package_fields(self._retry_after_self_lock_release(
1797
1838
  profile=profile,
1798
1839
  result=result,
1799
1840
  retry_call=lambda: self._facade.app_publish_verify(
1800
1841
  profile=profile,
1801
1842
  app_key=app_key,
1802
- expected_package_tag_id=expected_package_tag_id,
1843
+ expected_package_tag_id=expected_package_id,
1803
1844
  ),
1804
- )
1845
+ ))
1805
1846
 
1806
1847
  def _retry_after_self_lock_release(self, *, profile: str, result: JSONObject, retry_call) -> JSONObject:
1807
1848
  if not isinstance(result, dict) or result.get("status") != "failed" or result.get("error_code") != "APP_EDIT_LOCKED":
@@ -2057,6 +2098,29 @@ def _safe_tool_call(
2057
2098
  }
2058
2099
 
2059
2100
 
2101
+ def _publicize_package_fields(value):
2102
+ if isinstance(value, list):
2103
+ return [_publicize_package_fields(item) for item in value]
2104
+ if not isinstance(value, dict):
2105
+ return value
2106
+ key_map = {
2107
+ "tag_id": "package_id",
2108
+ "tag_ids": "package_ids",
2109
+ "tag_ids_before": "package_ids_before",
2110
+ "tag_ids_after": "package_ids_after",
2111
+ "tag_name": "package_name",
2112
+ "tag_icon": "icon",
2113
+ "package_tag_id": "package_id",
2114
+ "package_tag_ids": "package_ids",
2115
+ "expected_package_tag_id": "expected_package_id",
2116
+ }
2117
+ public: JSONObject = {}
2118
+ for key, item in value.items():
2119
+ public_key = key_map.get(key, key)
2120
+ public[public_key] = _publicize_package_fields(item)
2121
+ return public
2122
+
2123
+
2060
2124
  def _coerce_api_error(error: Exception) -> QingflowApiError:
2061
2125
  if isinstance(error, QingflowApiError):
2062
2126
  return error
@@ -2205,88 +2269,59 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2205
2269
  "tool_name": "chart_get",
2206
2270
  },
2207
2271
  },
2208
- "package_list": {
2209
- "allowed_keys": ["trial_status"],
2210
- "aliases": {"trialStatus": "trial_status"},
2211
- "allowed_values": {"trial_status": ["all", "trial", "formal"]},
2212
- "minimal_example": {
2213
- "profile": "default",
2214
- "trial_status": "all",
2215
- },
2216
- },
2217
- "package_resolve": {
2218
- "allowed_keys": ["package_name"],
2219
- "aliases": {"packageName": "package_name"},
2220
- "allowed_values": {},
2221
- "minimal_example": {
2222
- "profile": "default",
2223
- "package_name": "PLM(备用,施工中)",
2224
- },
2225
- },
2226
- "package_create": {
2227
- "allowed_keys": ["package_name", "icon", "color", "visibility"],
2228
- "aliases": {
2229
- "packageName": "package_name",
2230
- "iconName": "icon",
2231
- "iconColor": "color",
2232
- },
2233
- "allowed_values": deepcopy(_VISIBILITY_ALLOWED_VALUES),
2234
- "execution_notes": [
2235
- "create a package and optionally set visibility in the same call",
2236
- *_VISIBILITY_EXECUTION_NOTES,
2237
- ],
2238
- "minimal_example": {
2239
- "profile": "default",
2240
- "package_name": "项目管理",
2241
- "icon": "files-folder",
2242
- "color": "azure",
2243
- "visibility": deepcopy(_VISIBILITY_WORKSPACE_EXAMPLE),
2244
- },
2245
- "specific_visibility_example": {
2246
- "profile": "default",
2247
- "package_name": "项目管理",
2248
- "icon": "files-folder",
2249
- "color": "azure",
2250
- "visibility": deepcopy(_VISIBILITY_SPECIFIC_EXAMPLE),
2251
- },
2252
- },
2253
2272
  "package_get": {
2254
- "allowed_keys": ["tag_id"],
2255
- "aliases": {"tagId": "tag_id"},
2273
+ "allowed_keys": ["package_id"],
2274
+ "aliases": {"packageId": "package_id"},
2256
2275
  "allowed_values": {},
2257
2276
  "execution_notes": [
2258
- "returns package base info plus normalized visibility",
2277
+ "returns complete public package schema with package_id, package_name, icon, visibility, and items",
2278
+ "package_id maps internally to backend tagId; do not use tag_id in public calls",
2259
2279
  "visibility is normalized from backend MemberAuthInfoVO auth",
2260
2280
  ],
2261
2281
  "minimal_example": {
2262
2282
  "profile": "default",
2263
- "tag_id": 1001,
2283
+ "package_id": 1001,
2264
2284
  },
2265
2285
  },
2266
- "package_update": {
2267
- "allowed_keys": ["tag_id", "package_name", "icon", "color", "visibility"],
2286
+ "package_apply": {
2287
+ "allowed_keys": ["package_id", "package_name", "create_if_missing", "icon", "color", "visibility", "items", "allow_detach"],
2268
2288
  "aliases": {
2269
- "tagId": "tag_id",
2289
+ "packageId": "package_id",
2270
2290
  "packageName": "package_name",
2291
+ "createIfMissing": "create_if_missing",
2271
2292
  "iconName": "icon",
2272
2293
  "iconColor": "color",
2294
+ "allowDetach": "allow_detach",
2273
2295
  },
2274
2296
  "allowed_values": deepcopy(_VISIBILITY_ALLOWED_VALUES),
2275
2297
  "execution_notes": [
2276
- "update package name, icon, color, and/or visibility",
2298
+ "create or update package metadata, visibility, grouping, and ordering in one call",
2299
+ "package_id maps internally to backend tagId; do not use tag_id in public calls",
2300
+ "items is a full package layout tree; omitting existing app/portal items is blocked unless allow_detach=true",
2301
+ "item shapes: {type:'app', app_key}, {type:'portal', dash_key}, or {type:'group', group_id?, name, items:[...]}",
2277
2302
  *_VISIBILITY_EXECUTION_NOTES,
2278
2303
  ],
2279
2304
  "minimal_example": {
2280
2305
  "profile": "default",
2281
- "tag_id": 1001,
2306
+ "package_id": 1001,
2282
2307
  "package_name": "项目管理",
2283
2308
  "visibility": deepcopy(_VISIBILITY_WORKSPACE_EXAMPLE),
2309
+ "items": [{"type": "app", "app_key": "APP_KEY", "title": "项目台账"}],
2310
+ "allow_detach": False,
2284
2311
  },
2285
2312
  "specific_visibility_example": {
2286
2313
  "profile": "default",
2287
- "tag_id": 1001,
2314
+ "package_id": 1001,
2288
2315
  "visibility": deepcopy(_VISIBILITY_SPECIFIC_EXAMPLE),
2289
2316
  },
2317
+ "create_example": {
2318
+ "profile": "default",
2319
+ "package_name": "项目管理",
2320
+ "create_if_missing": True,
2321
+ "icon": "files-folder",
2322
+ "color": "azure",
2323
+ "visibility": deepcopy(_VISIBILITY_WORKSPACE_EXAMPLE),
2324
+ },
2290
2325
  },
2291
2326
  "solution_install": {
2292
2327
  "allowed_keys": ["solution_key", "being_copy_data", "solution_source"],
@@ -2350,28 +2385,14 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2350
2385
  "role_icon": "ex-user-outlined",
2351
2386
  },
2352
2387
  },
2353
- "package_attach_app": {
2354
- "allowed_keys": ["tag_id", "app_key"],
2355
- "aliases": {},
2356
- "allowed_values": {},
2357
- "execution_notes": [
2358
- "attach one existing app to one existing package",
2359
- "app_title is no longer accepted as a public selector; resolve the app first and pass app_key",
2360
- ],
2361
- "minimal_example": {
2362
- "profile": "default",
2363
- "tag_id": 1001,
2364
- "app_key": "APP_KEY",
2365
- },
2366
- },
2367
2388
  "app_resolve": {
2368
- "allowed_keys": ["app_key", "app_name", "package_tag_id"],
2369
- "aliases": {},
2389
+ "allowed_keys": ["app_key", "app_name", "package_id"],
2390
+ "aliases": {"packageId": "package_id"},
2370
2391
  "allowed_values": {},
2371
2392
  "execution_notes": [
2372
2393
  "use exactly one selector mode",
2373
2394
  "mode 1: app_key",
2374
- "mode 2: app_name + package_tag_id",
2395
+ "mode 2: app_name + package_id",
2375
2396
  ],
2376
2397
  "minimal_example": {
2377
2398
  "profile": "default",
@@ -2380,7 +2401,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2380
2401
  "package_scoped_example": {
2381
2402
  "profile": "default",
2382
2403
  "app_name": "研发项目管理",
2383
- "package_tag_id": 1001,
2404
+ "package_id": 1001,
2384
2405
  },
2385
2406
  },
2386
2407
  "app_release_edit_lock_if_mine": {
@@ -2505,10 +2526,11 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2505
2526
  },
2506
2527
  },
2507
2528
  "app_schema_plan": {
2508
- "allowed_keys": ["app_key", "package_tag_id", "app_name", "icon", "color", "visibility", "create_if_missing", "add_fields", "update_fields", "remove_fields"],
2529
+ "allowed_keys": ["app_key", "package_id", "app_name", "icon", "color", "visibility", "create_if_missing", "add_fields", "update_fields", "remove_fields"],
2509
2530
  "aliases": {
2510
2531
  "app_title": "app_name",
2511
2532
  "title": "app_name",
2533
+ "packageId": "package_id",
2512
2534
  "field.title": "field.name",
2513
2535
  "field.label": "field.name",
2514
2536
  "field.fields": "field.subfields",
@@ -2542,7 +2564,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2542
2564
  "minimal_example": {
2543
2565
  "profile": "default",
2544
2566
  "app_name": "研发项目管理",
2545
- "package_tag_id": 1001,
2567
+ "package_id": 1001,
2546
2568
  "icon": "template",
2547
2569
  "color": "emerald",
2548
2570
  "visibility": deepcopy(_VISIBILITY_WORKSPACE_EXAMPLE),
@@ -2569,10 +2591,11 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2569
2591
  },
2570
2592
  },
2571
2593
  "app_schema_apply": {
2572
- "allowed_keys": ["app_key", "package_tag_id", "app_name", "icon", "color", "visibility", "create_if_missing", "publish", "add_fields", "update_fields", "remove_fields"],
2594
+ "allowed_keys": ["app_key", "package_id", "app_name", "icon", "color", "visibility", "create_if_missing", "publish", "add_fields", "update_fields", "remove_fields"],
2573
2595
  "aliases": {
2574
2596
  "app_title": "app_name",
2575
2597
  "title": "app_name",
2598
+ "packageId": "package_id",
2576
2599
  "field.title": "field.name",
2577
2600
  "field.label": "field.name",
2578
2601
  "field.fields": "field.subfields",
@@ -2605,7 +2628,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2605
2628
  "execution_notes": [
2606
2629
  "use exactly one resource mode",
2607
2630
  "edit mode: app_key, optional app_name to rename the existing app",
2608
- "create mode: package_tag_id + app_name + create_if_missing=true",
2631
+ "create mode: package_id + app_name + create_if_missing=true",
2609
2632
  "create mode defaults new app visibility to workspace/not when visibility is omitted; edit mode preserves current visibility when omitted",
2610
2633
  *_VISIBILITY_EXECUTION_NOTES,
2611
2634
  "multiple relation fields are backend-risky; read verification.relation_field_limit_verified and warnings before declaring the schema stable",
@@ -2624,7 +2647,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
2624
2647
  "minimal_example": {
2625
2648
  "profile": "default",
2626
2649
  "app_name": "研发项目管理",
2627
- "package_tag_id": 1001,
2650
+ "package_id": 1001,
2628
2651
  "icon": "template",
2629
2652
  "color": "emerald",
2630
2653
  "visibility": deepcopy(_VISIBILITY_WORKSPACE_EXAMPLE),
@@ -3178,8 +3201,9 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
3178
3201
  },
3179
3202
  },
3180
3203
  "portal_apply": {
3181
- "allowed_keys": ["dash_key", "dash_name", "package_tag_id", "publish", "sections", "visibility", "auth", "icon", "color", "hide_copyright", "dash_global_config", "config"],
3204
+ "allowed_keys": ["dash_key", "dash_name", "package_id", "publish", "sections", "visibility", "auth", "icon", "color", "hide_copyright", "dash_global_config", "config"],
3182
3205
  "aliases": {
3206
+ "packageId": "package_id",
3183
3207
  "sourceType": "source_type",
3184
3208
  "chartRef": "chart_ref",
3185
3209
  "viewRef": "view_ref",
@@ -3196,10 +3220,10 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
3196
3220
  "execution_notes": [
3197
3221
  "use exactly one resource mode",
3198
3222
  "update mode: dash_key",
3199
- "create mode: package_tag_id + dash_name",
3223
+ "create mode: package_id + dash_name",
3200
3224
  "portal_apply uses replace semantics for sections",
3201
3225
  "remove a section by omitting it from the new sections list",
3202
- "package_tag_id is required when creating a new portal",
3226
+ "package_id is required when creating a new portal",
3203
3227
  "publish=false only guarantees draft and base-info updates; it does not claim live has changed",
3204
3228
  "chart_ref resolves by chart_id first, then exact unique chart_name",
3205
3229
  "view_ref resolves by view_key first, then exact unique view_name",
@@ -3211,7 +3235,7 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
3211
3235
  "minimal_example": {
3212
3236
  "profile": "default",
3213
3237
  "dash_name": "经营门户",
3214
- "package_tag_id": 1001,
3238
+ "package_id": 1001,
3215
3239
  "publish": True,
3216
3240
  "visibility": deepcopy(_VISIBILITY_WORKSPACE_EXAMPLE),
3217
3241
  "sections": [
@@ -3237,18 +3261,18 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
3237
3261
  },
3238
3262
  },
3239
3263
  "app_publish_verify": {
3240
- "allowed_keys": ["app_key", "expected_package_tag_id"],
3264
+ "allowed_keys": ["app_key", "expected_package_id"],
3241
3265
  "aliases": {},
3242
3266
  "allowed_values": {},
3243
3267
  "execution_notes": [
3244
3268
  "verifies that the current app draft has been published and is readable through the builder surface",
3245
- "expected_package_tag_id is optional and adds an extra package consistency check",
3269
+ "expected_package_id is optional and adds an extra package consistency check",
3246
3270
  "when verification fails because of an edit lock owned by the current user, retry after app_release_edit_lock_if_mine",
3247
3271
  ],
3248
3272
  "minimal_example": {
3249
3273
  "profile": "default",
3250
3274
  "app_key": "APP_KEY",
3251
- "expected_package_tag_id": 1001,
3275
+ "expected_package_id": 1001,
3252
3276
  },
3253
3277
  },
3254
3278
  "app_repair_code_blocks": {