@qingflow-tech/qingflow-app-user-mcp 1.0.44 → 1.1.1
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/npm/bin/qingflow-app-user-mcp.mjs +33 -2
- package/npm/lib/runtime.mjs +43 -2
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/skills/qingflow-app-user/SKILL.md +1 -1
- package/skills/qingflow-mcp-setup/SKILL.md +1 -1
- package/skills/qingflow-record-analysis/SKILL.md +1 -1
- package/skills/qingflow-record-delete/SKILL.md +1 -1
- package/skills/qingflow-record-import/SKILL.md +1 -1
- package/skills/qingflow-record-insert/SKILL.md +1 -1
- package/skills/qingflow-record-update/SKILL.md +1 -1
- package/skills/qingflow-task-ops/SKILL.md +1 -1
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/builder_facade/models.py +0 -39
- package/src/qingflow_mcp/builder_facade/service.py +262 -862
- package/src/qingflow_mcp/builder_facade/workflow_spec.py +111 -0
- package/src/qingflow_mcp/cli/commands/builder.py +44 -12
- package/src/qingflow_mcp/public_surface.py +2 -0
- package/src/qingflow_mcp/server_app_builder.py +16 -8
- package/src/qingflow_mcp/solution/compiler/__init__.py +1 -3
- package/src/qingflow_mcp/solution/executor.py +3 -133
- package/src/qingflow_mcp/tools/ai_builder_tools.py +92 -233
- package/src/qingflow_mcp/tools/solution_tools.py +30 -2
- package/src/qingflow_mcp/tools/workflow_tools.py +3 -31
- package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +0 -173
|
@@ -27,10 +27,6 @@ from ..builder_facade.models import (
|
|
|
27
27
|
FieldPatch,
|
|
28
28
|
FieldRemovePatch,
|
|
29
29
|
FieldUpdatePatch,
|
|
30
|
-
FlowPreset,
|
|
31
|
-
FlowNodePatch,
|
|
32
|
-
FlowPlanRequest,
|
|
33
|
-
FlowTransitionPatch,
|
|
34
30
|
LayoutApplyMode,
|
|
35
31
|
LayoutPlanRequest,
|
|
36
32
|
LayoutPreset,
|
|
@@ -70,7 +66,6 @@ from .qingbi_report_tools import QingbiReportTools
|
|
|
70
66
|
from .role_tools import RoleTools
|
|
71
67
|
from .solution_tools import SolutionTools
|
|
72
68
|
from .view_tools import ViewTools
|
|
73
|
-
from .workflow_tools import WorkflowTools
|
|
74
69
|
|
|
75
70
|
|
|
76
71
|
def _normalize_builder_view_key(value: str) -> str:
|
|
@@ -80,7 +75,6 @@ def _normalize_builder_view_key(value: str) -> str:
|
|
|
80
75
|
return raw
|
|
81
76
|
|
|
82
77
|
|
|
83
|
-
PUBLIC_STABLE_FLOW_NODE_TYPES = ["start", "approve", "fill", "copy", "webhook", "end"]
|
|
84
78
|
BUILDER_APPLY_SCHEMA_VERSION = "builder.apply.v1"
|
|
85
79
|
BUILDER_APPLY_TOOL_NAMES = {
|
|
86
80
|
"package_apply",
|
|
@@ -115,7 +109,6 @@ class AiBuilderTools(ToolBase):
|
|
|
115
109
|
buttons=CustomButtonTools(sessions, backend),
|
|
116
110
|
packages=PackageTools(sessions, backend),
|
|
117
111
|
views=ViewTools(sessions, backend),
|
|
118
|
-
workflows=WorkflowTools(sessions, backend),
|
|
119
112
|
portals=PortalTools(sessions, backend),
|
|
120
113
|
charts=QingbiReportTools(sessions, backend),
|
|
121
114
|
roles=RoleTools(sessions, backend),
|
|
@@ -455,22 +448,34 @@ class AiBuilderTools(ToolBase):
|
|
|
455
448
|
) -> JSONObject:
|
|
456
449
|
return self.app_layout_apply(profile=profile, app_key=app_key, mode=mode, publish=publish, sections=sections or [])
|
|
457
450
|
|
|
451
|
+
@mcp.tool()
|
|
452
|
+
def app_flow_get(
|
|
453
|
+
profile: str = DEFAULT_PROFILE,
|
|
454
|
+
app_key: str = "",
|
|
455
|
+
version_id: str = "",
|
|
456
|
+
) -> JSONObject:
|
|
457
|
+
return self.app_get_flow(profile=profile, app_key=app_key, version_id=version_id or None)
|
|
458
|
+
|
|
459
|
+
@mcp.tool()
|
|
460
|
+
def app_flow_get_schema(profile: str = DEFAULT_PROFILE, schema_version: str = "") -> JSONObject:
|
|
461
|
+
return self.app_flow_get_schema(profile=profile, schema_version=schema_version or None)
|
|
462
|
+
|
|
458
463
|
@mcp.tool()
|
|
459
464
|
def app_flow_apply(
|
|
460
465
|
profile: str = DEFAULT_PROFILE,
|
|
461
466
|
app_key: str = "",
|
|
462
|
-
mode: str = "replace",
|
|
463
467
|
publish: bool = True,
|
|
464
|
-
|
|
465
|
-
|
|
468
|
+
spec: JSONObject | None = None,
|
|
469
|
+
idempotency_key: str = "",
|
|
470
|
+
schema_version: str = "",
|
|
466
471
|
) -> JSONObject:
|
|
467
472
|
return self.app_flow_apply(
|
|
468
473
|
profile=profile,
|
|
469
474
|
app_key=app_key,
|
|
470
|
-
mode=mode,
|
|
471
475
|
publish=publish,
|
|
472
|
-
|
|
473
|
-
|
|
476
|
+
spec=spec or {},
|
|
477
|
+
idempotency_key=idempotency_key or None,
|
|
478
|
+
schema_version=schema_version or None,
|
|
474
479
|
)
|
|
475
480
|
|
|
476
481
|
@mcp.tool()
|
|
@@ -1370,26 +1375,25 @@ class AiBuilderTools(ToolBase):
|
|
|
1370
1375
|
suggested_next_call={"tool_name": "app_get_views", "arguments": {"profile": profile, "app_key": app_key}},
|
|
1371
1376
|
)
|
|
1372
1377
|
|
|
1373
|
-
@tool_cn_name("
|
|
1374
|
-
def
|
|
1375
|
-
""
|
|
1376
|
-
normalized_args = {"app_key": app_key}
|
|
1378
|
+
@tool_cn_name("Workflow Spec Schema")
|
|
1379
|
+
def app_flow_get_schema(self, *, profile: str, schema_version: str | None = None) -> JSONObject:
|
|
1380
|
+
normalized_args = {"schema_version": schema_version}
|
|
1377
1381
|
return _safe_tool_call(
|
|
1378
|
-
lambda: self._facade.
|
|
1379
|
-
error_code="
|
|
1382
|
+
lambda: self._facade.flow_get_schema(profile=profile, schema_version=schema_version),
|
|
1383
|
+
error_code="FLOW_SPEC_SCHEMA_FAILED",
|
|
1380
1384
|
normalized_args=normalized_args,
|
|
1381
|
-
suggested_next_call={"tool_name": "
|
|
1385
|
+
suggested_next_call={"tool_name": "app_flow_get_schema", "arguments": {"profile": profile, **normalized_args}},
|
|
1382
1386
|
)
|
|
1383
1387
|
|
|
1384
|
-
@tool_cn_name("
|
|
1385
|
-
def app_get_flow(self, *, profile: str, app_key: str) -> JSONObject:
|
|
1388
|
+
@tool_cn_name("Workflow Spec 读取")
|
|
1389
|
+
def app_get_flow(self, *, profile: str, app_key: str, version_id: str | None = None) -> JSONObject:
|
|
1386
1390
|
"""执行应用相关逻辑。"""
|
|
1387
|
-
normalized_args = {"app_key": app_key}
|
|
1391
|
+
normalized_args = {"app_key": app_key, "version_id": version_id}
|
|
1388
1392
|
return _safe_tool_call(
|
|
1389
|
-
lambda: self._facade.
|
|
1393
|
+
lambda: self._facade.flow_get(profile=profile, app_key=app_key, version_id=version_id),
|
|
1390
1394
|
error_code="APP_GET_FLOW_FAILED",
|
|
1391
1395
|
normalized_args=normalized_args,
|
|
1392
|
-
suggested_next_call={"tool_name": "
|
|
1396
|
+
suggested_next_call={"tool_name": "app_flow_get", "arguments": {"profile": profile, "app_key": app_key}},
|
|
1393
1397
|
)
|
|
1394
1398
|
|
|
1395
1399
|
@tool_cn_name("应用图表摘要读取")
|
|
@@ -1600,52 +1604,6 @@ class AiBuilderTools(ToolBase):
|
|
|
1600
1604
|
suggested_next_call={"tool_name": "app_layout_plan", "arguments": {"profile": profile, **normalized_request}},
|
|
1601
1605
|
)
|
|
1602
1606
|
|
|
1603
|
-
@tool_cn_name("应用流程规划")
|
|
1604
|
-
def app_flow_plan(
|
|
1605
|
-
self,
|
|
1606
|
-
*,
|
|
1607
|
-
profile: str,
|
|
1608
|
-
app_key: str,
|
|
1609
|
-
mode: str = "replace",
|
|
1610
|
-
nodes: list[JSONObject] | None = None,
|
|
1611
|
-
transitions: list[JSONObject] | None = None,
|
|
1612
|
-
preset: str | None = None,
|
|
1613
|
-
) -> JSONObject:
|
|
1614
|
-
"""执行应用相关逻辑。"""
|
|
1615
|
-
try:
|
|
1616
|
-
request = FlowPlanRequest.model_validate(
|
|
1617
|
-
{
|
|
1618
|
-
"app_key": app_key,
|
|
1619
|
-
"mode": mode,
|
|
1620
|
-
"nodes": nodes or [],
|
|
1621
|
-
"transitions": transitions or [],
|
|
1622
|
-
"preset": preset,
|
|
1623
|
-
}
|
|
1624
|
-
)
|
|
1625
|
-
except ValidationError as exc:
|
|
1626
|
-
return _validation_failure(
|
|
1627
|
-
str(exc),
|
|
1628
|
-
tool_name="app_flow_plan",
|
|
1629
|
-
exc=exc,
|
|
1630
|
-
suggested_next_call={
|
|
1631
|
-
"tool_name": "app_flow_plan",
|
|
1632
|
-
"arguments": {
|
|
1633
|
-
"profile": profile,
|
|
1634
|
-
"app_key": app_key,
|
|
1635
|
-
"mode": "replace",
|
|
1636
|
-
"preset": "basic_approval",
|
|
1637
|
-
"nodes": [],
|
|
1638
|
-
"transitions": [],
|
|
1639
|
-
},
|
|
1640
|
-
},
|
|
1641
|
-
)
|
|
1642
|
-
return _safe_tool_call(
|
|
1643
|
-
lambda: self._facade.app_flow_plan(profile=profile, request=request),
|
|
1644
|
-
error_code="FLOW_PLAN_FAILED",
|
|
1645
|
-
normalized_args=request.model_dump(mode="json"),
|
|
1646
|
-
suggested_next_call={"tool_name": "app_flow_plan", "arguments": {"profile": profile, **request.model_dump(mode="json")}},
|
|
1647
|
-
)
|
|
1648
|
-
|
|
1649
1607
|
@tool_cn_name("应用视图规划")
|
|
1650
1608
|
def app_views_plan(
|
|
1651
1609
|
self,
|
|
@@ -2376,111 +2334,51 @@ class AiBuilderTools(ToolBase):
|
|
|
2376
2334
|
*,
|
|
2377
2335
|
profile: str,
|
|
2378
2336
|
app_key: str,
|
|
2379
|
-
|
|
2337
|
+
spec: JSONObject,
|
|
2380
2338
|
publish: bool = True,
|
|
2381
|
-
|
|
2382
|
-
|
|
2339
|
+
idempotency_key: str | None = None,
|
|
2340
|
+
schema_version: str | None = None,
|
|
2383
2341
|
) -> JSONObject:
|
|
2384
2342
|
"""执行应用相关逻辑。"""
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
app_key=app_key,
|
|
2388
|
-
mode=mode,
|
|
2389
|
-
publish=publish,
|
|
2390
|
-
nodes=nodes,
|
|
2391
|
-
transitions=transitions,
|
|
2392
|
-
)
|
|
2393
|
-
result = self._retry_after_self_lock_release(
|
|
2394
|
-
profile=profile,
|
|
2395
|
-
result=result,
|
|
2396
|
-
retry_call=lambda: self._app_flow_apply_once(
|
|
2397
|
-
profile=profile,
|
|
2398
|
-
app_key=app_key,
|
|
2399
|
-
mode=mode,
|
|
2400
|
-
publish=publish,
|
|
2401
|
-
nodes=nodes,
|
|
2402
|
-
transitions=transitions,
|
|
2403
|
-
),
|
|
2404
|
-
)
|
|
2405
|
-
return _attach_builder_apply_envelope("app_flow_apply", result)
|
|
2406
|
-
|
|
2407
|
-
def _app_flow_apply_once(
|
|
2408
|
-
self,
|
|
2409
|
-
*,
|
|
2410
|
-
profile: str,
|
|
2411
|
-
app_key: str,
|
|
2412
|
-
mode: str = "replace",
|
|
2413
|
-
publish: bool = True,
|
|
2414
|
-
nodes: list[JSONObject],
|
|
2415
|
-
transitions: list[JSONObject],
|
|
2416
|
-
) -> JSONObject:
|
|
2417
|
-
"""执行内部辅助逻辑。"""
|
|
2418
|
-
plan_result = self._rewrite_plan_result_for_apply(
|
|
2419
|
-
result=self.app_flow_plan(
|
|
2420
|
-
profile=profile,
|
|
2421
|
-
app_key=app_key,
|
|
2422
|
-
mode=mode,
|
|
2423
|
-
nodes=nodes,
|
|
2424
|
-
transitions=transitions,
|
|
2425
|
-
preset=None,
|
|
2426
|
-
),
|
|
2427
|
-
profile=profile,
|
|
2428
|
-
publish=publish,
|
|
2429
|
-
plan_tool_name="app_flow_plan",
|
|
2430
|
-
apply_tool_name="app_flow_apply",
|
|
2431
|
-
)
|
|
2432
|
-
if not isinstance(plan_result, dict) or plan_result.get("status") != "success":
|
|
2433
|
-
return plan_result
|
|
2434
|
-
plan_args = plan_result.get("normalized_args")
|
|
2435
|
-
if not isinstance(plan_args, dict):
|
|
2436
|
-
plan_args = {}
|
|
2437
|
-
try:
|
|
2438
|
-
request = FlowPlanRequest.model_validate(
|
|
2439
|
-
{
|
|
2440
|
-
"app_key": plan_args.get("app_key") or app_key,
|
|
2441
|
-
"mode": plan_args.get("mode") or mode,
|
|
2442
|
-
"nodes": plan_args.get("nodes") or [],
|
|
2443
|
-
"transitions": plan_args.get("transitions") or [],
|
|
2444
|
-
"preset": None,
|
|
2445
|
-
}
|
|
2446
|
-
)
|
|
2447
|
-
except ValidationError as exc:
|
|
2448
|
-
return _validation_failure(
|
|
2449
|
-
str(exc),
|
|
2343
|
+
if not isinstance(spec, dict) or not spec:
|
|
2344
|
+
return _config_failure(
|
|
2450
2345
|
tool_name="app_flow_apply",
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
"tool_name": "app_flow_apply",
|
|
2454
|
-
"arguments": {
|
|
2455
|
-
"profile": profile,
|
|
2456
|
-
"app_key": str(plan_args.get("app_key") or app_key),
|
|
2457
|
-
"mode": str(plan_args.get("mode") or "replace"),
|
|
2458
|
-
"publish": publish,
|
|
2459
|
-
"nodes": plan_args.get("nodes") or [{"id": "start", "type": "start", "name": "发起"}],
|
|
2460
|
-
"transitions": plan_args.get("transitions") or [],
|
|
2461
|
-
},
|
|
2462
|
-
},
|
|
2346
|
+
message="app_flow_apply requires a non-empty WorkflowSpecDTO `spec` object.",
|
|
2347
|
+
fix_hint="Call app_flow_get_schema, then app_flow_get for GET-first baseline, patch spec, and apply.",
|
|
2463
2348
|
)
|
|
2464
2349
|
normalized_args = {
|
|
2465
|
-
"app_key":
|
|
2466
|
-
"mode": request.mode,
|
|
2350
|
+
"app_key": app_key,
|
|
2467
2351
|
"publish": publish,
|
|
2468
|
-
"
|
|
2469
|
-
"
|
|
2352
|
+
"spec": spec,
|
|
2353
|
+
"idempotency_key": idempotency_key,
|
|
2354
|
+
"schema_version": schema_version,
|
|
2470
2355
|
}
|
|
2471
|
-
|
|
2472
|
-
lambda: self._facade.
|
|
2356
|
+
result = _safe_tool_call(
|
|
2357
|
+
lambda: self._facade.flow_apply(
|
|
2473
2358
|
profile=profile,
|
|
2474
|
-
app_key=
|
|
2475
|
-
|
|
2359
|
+
app_key=app_key,
|
|
2360
|
+
spec=spec,
|
|
2476
2361
|
publish=publish,
|
|
2477
|
-
|
|
2478
|
-
|
|
2362
|
+
idempotency_key=idempotency_key,
|
|
2363
|
+
schema_version=schema_version,
|
|
2479
2364
|
),
|
|
2480
2365
|
error_code="FLOW_APPLY_FAILED",
|
|
2481
2366
|
normalized_args=normalized_args,
|
|
2482
2367
|
suggested_next_call={"tool_name": "app_flow_apply", "arguments": {"profile": profile, **normalized_args}},
|
|
2483
2368
|
)
|
|
2369
|
+
result = self._retry_after_self_lock_release(
|
|
2370
|
+
profile=profile,
|
|
2371
|
+
result=result,
|
|
2372
|
+
retry_call=lambda: self._facade.flow_apply(
|
|
2373
|
+
profile=profile,
|
|
2374
|
+
app_key=app_key,
|
|
2375
|
+
spec=spec,
|
|
2376
|
+
publish=publish,
|
|
2377
|
+
idempotency_key=idempotency_key,
|
|
2378
|
+
schema_version=schema_version,
|
|
2379
|
+
),
|
|
2380
|
+
)
|
|
2381
|
+
return _attach_builder_apply_envelope("app_flow_apply", result)
|
|
2484
2382
|
|
|
2485
2383
|
@tool_cn_name("应用视图应用")
|
|
2486
2384
|
def app_views_apply(
|
|
@@ -5805,94 +5703,56 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
5805
5703
|
"sections": [{"type": "paragraph", "paragraph_id": "basic", "title": "基础信息", "rows": [["项目名称", "项目负责人", "项目阶段", "优先级"]]}],
|
|
5806
5704
|
},
|
|
5807
5705
|
},
|
|
5808
|
-
"
|
|
5809
|
-
"allowed_keys": ["
|
|
5810
|
-
"aliases": {
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
"
|
|
5814
|
-
"
|
|
5815
|
-
"
|
|
5816
|
-
"node.member_names": "node.assignees.member_names",
|
|
5817
|
-
"node.member_emails": "node.assignees.member_emails",
|
|
5818
|
-
"node.member_uids": "node.assignees.member_uids",
|
|
5819
|
-
"node.editable_fields": "node.permissions.editable_fields",
|
|
5820
|
-
"default_approval": "basic_approval",
|
|
5821
|
-
},
|
|
5822
|
-
"allowed_values": {
|
|
5823
|
-
"mode": ["replace"],
|
|
5824
|
-
"preset": [member.value for member in FlowPreset],
|
|
5825
|
-
"node.type": PUBLIC_STABLE_FLOW_NODE_TYPES,
|
|
5826
|
-
},
|
|
5827
|
-
"dependency_hints": [
|
|
5828
|
-
"approval-style workflows require an explicit business status select field before app_flow_apply, such as 状态 / 处理状态 / 审批状态 / 工单状态",
|
|
5829
|
-
"approve/fill/copy nodes require at least one assignee",
|
|
5706
|
+
"app_flow_get_schema": {
|
|
5707
|
+
"allowed_keys": ["schema_version"],
|
|
5708
|
+
"aliases": {"schemaVersion": "schema_version"},
|
|
5709
|
+
"allowed_values": {},
|
|
5710
|
+
"execution_notes": [
|
|
5711
|
+
"returns WorkflowSpec JSON Schema from /workflow/spec/schema",
|
|
5712
|
+
"call this before authoring a new spec or validating spec shape",
|
|
5713
|
+
"worksheet-level approval deduplication toggles (legacy global settings) are not yet part of WorkflowSpec",
|
|
5830
5714
|
],
|
|
5715
|
+
"minimal_example": {
|
|
5716
|
+
"profile": "default",
|
|
5717
|
+
"schema_version": "vnext-2026-06",
|
|
5718
|
+
},
|
|
5719
|
+
},
|
|
5720
|
+
"app_flow_get": {
|
|
5721
|
+
"allowed_keys": ["app_key", "version_id"],
|
|
5722
|
+
"aliases": {"versionId": "version_id"},
|
|
5723
|
+
"allowed_values": {},
|
|
5831
5724
|
"execution_notes": [
|
|
5832
|
-
"
|
|
5833
|
-
"
|
|
5834
|
-
"do not create platform system workflow fields such as 当前流程状态 / 当前处理人 / 当前处理节点 / 流程标题; use an explicit business status field instead",
|
|
5725
|
+
"returns current WorkflowSpecDTO for one app via GET /workflow/spec",
|
|
5726
|
+
"use GET-first before patching and app_flow_apply",
|
|
5835
5727
|
],
|
|
5836
5728
|
"minimal_example": {
|
|
5837
5729
|
"profile": "default",
|
|
5838
5730
|
"app_key": "APP_KEY",
|
|
5839
|
-
"mode": "replace",
|
|
5840
|
-
"preset": "basic_approval",
|
|
5841
|
-
"nodes": [
|
|
5842
|
-
{
|
|
5843
|
-
"id": "approve_1",
|
|
5844
|
-
"type": "approve",
|
|
5845
|
-
"name": "部门审批",
|
|
5846
|
-
"assignees": {"role_names": ["项目经理"]},
|
|
5847
|
-
"permissions": {"editable_fields": ["状态", "审批意见"]},
|
|
5848
|
-
}
|
|
5849
|
-
],
|
|
5850
|
-
"transitions": [],
|
|
5851
5731
|
},
|
|
5852
5732
|
},
|
|
5853
5733
|
"app_flow_apply": {
|
|
5854
|
-
"allowed_keys": ["app_key", "
|
|
5734
|
+
"allowed_keys": ["app_key", "publish", "spec", "idempotency_key", "schema_version"],
|
|
5855
5735
|
"aliases": {
|
|
5856
|
-
"
|
|
5857
|
-
"
|
|
5858
|
-
"node.role_ids": "node.assignees.role_ids",
|
|
5859
|
-
"node.member_names": "node.assignees.member_names",
|
|
5860
|
-
"node.member_emails": "node.assignees.member_emails",
|
|
5861
|
-
"node.member_uids": "node.assignees.member_uids",
|
|
5862
|
-
"node.editable_fields": "node.permissions.editable_fields",
|
|
5863
|
-
},
|
|
5864
|
-
"allowed_values": {
|
|
5865
|
-
"mode": ["replace"],
|
|
5866
|
-
"node.type": PUBLIC_STABLE_FLOW_NODE_TYPES,
|
|
5736
|
+
"schemaVersion": "schema_version",
|
|
5737
|
+
"idempotencyKey": "idempotency_key",
|
|
5867
5738
|
},
|
|
5739
|
+
"allowed_values": {},
|
|
5868
5740
|
"dependency_hints": [
|
|
5869
|
-
"
|
|
5870
|
-
"approve/fill/copy nodes require at least one assignee",
|
|
5741
|
+
"spec must be a complete WorkflowSpecDTO object (replace-only apply)",
|
|
5871
5742
|
],
|
|
5872
5743
|
"execution_notes": [
|
|
5873
|
-
"
|
|
5874
|
-
"
|
|
5875
|
-
"
|
|
5876
|
-
"do not create platform system workflow fields such as 当前流程状态 / 当前处理人 / 当前处理节点 / 流程标题; use an explicit business status field instead",
|
|
5877
|
-
"workflow verification only covers linear node structure in the public tool surface",
|
|
5744
|
+
"posts to /workflow/spec:apply with appKey, idempotencyKey, schemaVersion, and spec",
|
|
5745
|
+
"verification uses appliedSpec, diffSummary, and semanticLint from the apply response",
|
|
5746
|
+
"publish=false keeps changes in draft when supported by the backend",
|
|
5878
5747
|
],
|
|
5879
5748
|
"minimal_example": {
|
|
5880
5749
|
"profile": "default",
|
|
5881
5750
|
"app_key": "APP_KEY",
|
|
5882
|
-
"mode": "replace",
|
|
5883
5751
|
"publish": True,
|
|
5884
|
-
"
|
|
5885
|
-
{"id": "
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
"type": "approve",
|
|
5889
|
-
"name": "部门审批",
|
|
5890
|
-
"assignees": {"role_names": ["项目经理"]},
|
|
5891
|
-
"permissions": {"editable_fields": ["状态", "审批意见"]},
|
|
5892
|
-
},
|
|
5893
|
-
{"id": "end", "type": "end", "name": "结束"},
|
|
5894
|
-
],
|
|
5895
|
-
"transitions": [{"from": "start", "to": "approve_1"}, {"from": "approve_1", "to": "end"}],
|
|
5752
|
+
"spec": {
|
|
5753
|
+
"nodes": [{"id": "n1", "type": "APPLICANT", "name": "发起"}],
|
|
5754
|
+
"transitions": [],
|
|
5755
|
+
},
|
|
5896
5756
|
},
|
|
5897
5757
|
},
|
|
5898
5758
|
"app_views_plan": {
|
|
@@ -6242,8 +6102,8 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
6242
6102
|
"aliases": {},
|
|
6243
6103
|
"allowed_values": {},
|
|
6244
6104
|
"execution_notes": [
|
|
6245
|
-
"returns
|
|
6246
|
-
"use
|
|
6105
|
+
"returns WorkflowSpecDTO for one app (alias of app_flow_get)",
|
|
6106
|
+
"use app_flow_get_schema then app_flow_get before app_flow_apply",
|
|
6247
6107
|
],
|
|
6248
6108
|
"minimal_example": {
|
|
6249
6109
|
"profile": "default",
|
|
@@ -6549,7 +6409,6 @@ _BUILDER_TOOL_CONTRACTS: dict[str, JSONObject] = {
|
|
|
6549
6409
|
_PRIVATE_BUILDER_TOOL_CONTRACTS = {
|
|
6550
6410
|
"app_schema_plan",
|
|
6551
6411
|
"app_layout_plan",
|
|
6552
|
-
"app_flow_plan",
|
|
6553
6412
|
"app_views_plan",
|
|
6554
6413
|
}
|
|
6555
6414
|
|
|
@@ -38,7 +38,6 @@ from .qingbi_report_tools import QingbiReportTools
|
|
|
38
38
|
from .record_tools import RecordTools
|
|
39
39
|
from .role_tools import RoleTools
|
|
40
40
|
from .view_tools import ViewTools
|
|
41
|
-
from .workflow_tools import WorkflowTools
|
|
42
41
|
from .workspace_tools import WorkspaceTools
|
|
43
42
|
|
|
44
43
|
STAGED_BUILD_MODES = {"preflight", "plan", "apply", "repair"}
|
|
@@ -737,6 +736,36 @@ class SolutionTools(ToolBase):
|
|
|
737
736
|
) -> dict[str, Any]:
|
|
738
737
|
"""执行方案相关逻辑。"""
|
|
739
738
|
mode = _normalize_staged_build_mode(mode)
|
|
739
|
+
app_key = str(flow_spec.get("app_key") or "").strip()
|
|
740
|
+
spec_payload = flow_spec.get("spec")
|
|
741
|
+
if app_key and isinstance(spec_payload, dict) and spec_payload:
|
|
742
|
+
from .ai_builder_tools import AiBuilderTools
|
|
743
|
+
|
|
744
|
+
builder = AiBuilderTools(self.sessions, self.backend)
|
|
745
|
+
if mode in {"preflight", "plan"}:
|
|
746
|
+
return {
|
|
747
|
+
"build_id": build_id or _generate_build_id(run_label=run_label, stage_name="flow"),
|
|
748
|
+
"mode": mode,
|
|
749
|
+
"stage": "flow",
|
|
750
|
+
"status": "planned" if mode == "plan" else "preflighted",
|
|
751
|
+
"normalized_args": {"app_key": app_key, "spec": spec_payload},
|
|
752
|
+
"tool_name": "solution_build_flow",
|
|
753
|
+
}
|
|
754
|
+
result = builder.app_flow_apply(
|
|
755
|
+
profile=profile,
|
|
756
|
+
app_key=app_key,
|
|
757
|
+
spec=spec_payload,
|
|
758
|
+
publish=publish,
|
|
759
|
+
schema_version=flow_spec.get("schema_version") or flow_spec.get("schemaVersion"),
|
|
760
|
+
)
|
|
761
|
+
return {
|
|
762
|
+
"build_id": build_id,
|
|
763
|
+
"mode": mode,
|
|
764
|
+
"stage": "flow",
|
|
765
|
+
"status": result.get("status"),
|
|
766
|
+
"result": result,
|
|
767
|
+
"tool_name": "solution_build_flow",
|
|
768
|
+
}
|
|
740
769
|
return self._stage_build(
|
|
741
770
|
profile=profile,
|
|
742
771
|
mode=mode,
|
|
@@ -1409,7 +1438,6 @@ class SolutionTools(ToolBase):
|
|
|
1409
1438
|
role_tools=RoleTools(self.sessions, self.backend),
|
|
1410
1439
|
app_tools=AppTools(self.sessions, self.backend),
|
|
1411
1440
|
record_tools=RecordTools(self.sessions, self.backend),
|
|
1412
|
-
workflow_tools=WorkflowTools(self.sessions, self.backend),
|
|
1413
1441
|
view_tools=ViewTools(self.sessions, self.backend),
|
|
1414
1442
|
chart_tools=QingbiReportTools(self.sessions, self.backend),
|
|
1415
1443
|
portal_tools=PortalTools(self.sessions, self.backend),
|
|
@@ -14,25 +14,13 @@ class WorkflowTools(ToolBase):
|
|
|
14
14
|
|
|
15
15
|
类型:流程配置工具。
|
|
16
16
|
主要职责:
|
|
17
|
-
1.
|
|
18
|
-
2.
|
|
19
|
-
|
|
17
|
+
1. 支持流程运行时校验与调试辅助能力;
|
|
18
|
+
2. 保留 legacy 节点写路径供内部/测试直接调用(非 MCP 公开)。
|
|
19
|
+
设计期流程配置读取统一走 WorkflowSpec(app_flow_get / GET /api/workflow/spec)。
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
22
|
def register(self, mcp: FastMCP) -> None:
|
|
23
23
|
"""注册当前工具到 MCP 服务。"""
|
|
24
|
-
@mcp.tool()
|
|
25
|
-
def workflow_list_nodes(profile: str = DEFAULT_PROFILE, app_key: str = "") -> JSONObject:
|
|
26
|
-
return self.workflow_list_nodes(profile=profile, app_key=app_key)
|
|
27
|
-
|
|
28
|
-
@mcp.tool()
|
|
29
|
-
def workflow_get_node_detail(profile: str = DEFAULT_PROFILE, app_key: str = "", audit_node_id: int = 0) -> JSONObject:
|
|
30
|
-
return self.workflow_get_node_detail(profile=profile, app_key=app_key, audit_node_id=audit_node_id)
|
|
31
|
-
|
|
32
|
-
@mcp.tool()
|
|
33
|
-
def workflow_get_global_settings(profile: str = DEFAULT_PROFILE, app_key: str = "") -> JSONObject:
|
|
34
|
-
return self.workflow_get_global_settings(profile=profile, app_key=app_key)
|
|
35
|
-
|
|
36
24
|
@mcp.tool()
|
|
37
25
|
def workflow_get_future_nodes(profile: str = DEFAULT_PROFILE, app_key: str = "", apply_id: int = 0) -> JSONObject:
|
|
38
26
|
return self.workflow_get_future_nodes(profile=profile, app_key=app_key, apply_id=apply_id)
|
|
@@ -53,22 +41,6 @@ class WorkflowTools(ToolBase):
|
|
|
53
41
|
audit_node_id=audit_node_id,
|
|
54
42
|
)
|
|
55
43
|
|
|
56
|
-
@mcp.tool()
|
|
57
|
-
def workflow_get_qsource_active(profile: str = DEFAULT_PROFILE, app_key: str = "", qsource_id: int = 0) -> JSONObject:
|
|
58
|
-
return self.workflow_get_qsource_active(profile=profile, app_key=app_key, qsource_id=qsource_id)
|
|
59
|
-
|
|
60
|
-
@mcp.tool()
|
|
61
|
-
def workflow_get_qsource_passive(profile: str = DEFAULT_PROFILE, app_key: str = "", qsource_id: int = 0) -> JSONObject:
|
|
62
|
-
return self.workflow_get_qsource_passive(profile=profile, app_key=app_key, qsource_id=qsource_id)
|
|
63
|
-
|
|
64
|
-
@mcp.tool()
|
|
65
|
-
def workflow_get_editable_question_ids(profile: str = DEFAULT_PROFILE, app_key: str = "", audit_node_id: int = 0) -> JSONObject:
|
|
66
|
-
return self.workflow_get_editable_question_ids(profile=profile, app_key=app_key, audit_node_id=audit_node_id)
|
|
67
|
-
|
|
68
|
-
@mcp.tool()
|
|
69
|
-
def workflow_get_print_nodes(profile: str = DEFAULT_PROFILE, app_key: str = "") -> JSONObject:
|
|
70
|
-
return self.workflow_get_print_nodes(profile=profile, app_key=app_key)
|
|
71
|
-
|
|
72
44
|
@tool_cn_name("流程节点列表")
|
|
73
45
|
def workflow_list_nodes(self, *, profile: str, app_key: str) -> JSONObject:
|
|
74
46
|
"""执行流程相关逻辑。"""
|