@qingflow-tech/qingflow-app-user-mcp 1.0.40 → 1.0.42
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 -4
- package/docs/local-agent-install.md +4 -4
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/skills/qingflow-app-user/SKILL.md +5 -3
- package/skills/qingflow-mcp-setup/SKILL.md +2 -0
- package/skills/qingflow-record-analysis/SKILL.md +3 -1
- package/skills/qingflow-record-delete/SKILL.md +2 -0
- package/skills/qingflow-record-import/SKILL.md +29 -0
- package/skills/qingflow-record-insert/SKILL.md +24 -1
- package/skills/qingflow-record-update/SKILL.md +3 -0
- package/skills/qingflow-task-ops/SKILL.md +2 -0
- package/src/qingflow_mcp/builder_facade/models.py +183 -0
- package/src/qingflow_mcp/builder_facade/service.py +823 -75
- package/src/qingflow_mcp/cli/commands/builder.py +80 -6
- package/src/qingflow_mcp/cli/formatters.py +1 -0
- package/src/qingflow_mcp/cli/main.py +2 -0
- package/src/qingflow_mcp/response_trim.py +6 -4
- package/src/qingflow_mcp/tools/ai_builder_tools.py +388 -17
- package/src/qingflow_mcp/tools/record_tools.py +28 -2
- package/skills/qingflow-app-builder/SKILL.md +0 -280
- package/skills/qingflow-app-builder/agents/openai.yaml +0 -4
- package/skills/qingflow-app-builder/references/create-app.md +0 -160
- package/skills/qingflow-app-builder/references/environments.md +0 -63
- package/skills/qingflow-app-builder/references/flow-actors-and-permissions.md +0 -123
- package/skills/qingflow-app-builder/references/gotchas.md +0 -107
- package/skills/qingflow-app-builder/references/match-rules.md +0 -129
- package/skills/qingflow-app-builder/references/public-surface-sync.md +0 -75
- package/skills/qingflow-app-builder/references/solution-playbooks.md +0 -52
- package/skills/qingflow-app-builder/references/tool-selection.md +0 -106
- package/skills/qingflow-app-builder/references/update-flow.md +0 -158
- package/skills/qingflow-app-builder/references/update-layout.md +0 -68
- package/skills/qingflow-app-builder/references/update-schema.md +0 -75
- package/skills/qingflow-app-builder/references/update-views.md +0 -286
- package/skills/qingflow-app-builder-code-integrations/SKILL.md +0 -137
- package/skills/qingflow-app-builder-code-integrations/agents/openai.yaml +0 -4
- package/skills/qingflow-app-builder-code-integrations/references/code-block.md +0 -66
- package/skills/qingflow-app-builder-code-integrations/references/q-linker.md +0 -77
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
# Update Flow
|
|
2
|
-
|
|
3
|
-
Use this when the app already exists and the task is only about workflow.
|
|
4
|
-
|
|
5
|
-
## Minimal sequence
|
|
6
|
-
|
|
7
|
-
1. `builder_tool_contract(tool_name="app_flow_apply")`
|
|
8
|
-
2. `app_get_fields`
|
|
9
|
-
3. `app_get_flow`
|
|
10
|
-
4. `role_search` or `member_search`
|
|
11
|
-
5. `role_create` if the user wants a reusable directory role and no good role exists
|
|
12
|
-
6. start from a canonical preset when possible
|
|
13
|
-
7. patch the skeleton instead of freehanding a full graph
|
|
14
|
-
8. reuse preset node ids when patching:
|
|
15
|
-
- `basic_approval` -> patch `approve_1`
|
|
16
|
-
- `basic_fill_then_approve` -> patch `fill_1` and `approve_1`
|
|
17
|
-
Do not add a second approval/fill node with a new id unless you are intentionally replacing the skeleton.
|
|
18
|
-
The MCP now auto-aligns the simplest single-node preset overrides, but still prefer explicit preset ids so the merged graph stays predictable.
|
|
19
|
-
9. `app_flow_apply`
|
|
20
|
-
10. `app_get_flow` when apply returns `partial_success` or the user asked for verification
|
|
21
|
-
|
|
22
|
-
If you are unsure about presets or node shapes, call `builder_tool_contract(tool_name="app_flow_apply")` before guessing.
|
|
23
|
-
|
|
24
|
-
## Example
|
|
25
|
-
|
|
26
|
-
Canonical preset mapping:
|
|
27
|
-
|
|
28
|
-
- “默认审批/基础审批/普通审批” -> `basic_approval`
|
|
29
|
-
- “先填报再审批/提交后审批” -> `basic_fill_then_approve`
|
|
30
|
-
|
|
31
|
-
Apply a simple approval flow with a role assignee and node-level editable fields:
|
|
32
|
-
|
|
33
|
-
```json
|
|
34
|
-
{
|
|
35
|
-
"tool_name": "app_flow_apply",
|
|
36
|
-
"arguments": {
|
|
37
|
-
"profile": "default",
|
|
38
|
-
"app_key": "APP_123",
|
|
39
|
-
"preset": "basic_approval",
|
|
40
|
-
"publish": true,
|
|
41
|
-
"nodes": [
|
|
42
|
-
{
|
|
43
|
-
"id": "approve_1",
|
|
44
|
-
"type": "approve",
|
|
45
|
-
"name": "部门审批",
|
|
46
|
-
"assignees": {
|
|
47
|
-
"role_names": ["项目经理"]
|
|
48
|
-
},
|
|
49
|
-
"permissions": {
|
|
50
|
-
"editable_fields": ["状态", "审批意见"]
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
]
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
For flexible business requirements, do not jump straight to a full custom graph. Use this safer pattern:
|
|
59
|
-
|
|
60
|
-
1. build a base skeleton from a preset
|
|
61
|
-
2. identify the business-specific changes
|
|
62
|
-
3. patch nodes/transitions explicitly
|
|
63
|
-
|
|
64
|
-
Public flow building is intentionally limited to linear workflows. Use only:
|
|
65
|
-
|
|
66
|
-
- `start`
|
|
67
|
-
- `approve`
|
|
68
|
-
- `fill`
|
|
69
|
-
- `copy`
|
|
70
|
-
- `webhook`
|
|
71
|
-
- `end`
|
|
72
|
-
|
|
73
|
-
Do not generate `branch` or `condition` nodes through `app_flow_apply`. The backend workflow route is not front-end stable for those node types, and MCP now returns `FLOW_NODE_TYPE_UNSUPPORTED` instead of writing a visually broken flow.
|
|
74
|
-
After `app_flow_apply` returns blocking issues or canonical arguments, prefer reusing its `suggested_next_call.arguments` directly. Do not rewrite the result into internal fields such as `role_entries` or `editable_que_ids`.
|
|
75
|
-
When you patch a preset, patch the preset node itself. Do not leave the preset approval node unassigned while adding a second custom approval node.
|
|
76
|
-
|
|
77
|
-
## Common failures
|
|
78
|
-
|
|
79
|
-
### `FLOW_ASSIGNEE_REQUIRED`
|
|
80
|
-
|
|
81
|
-
Approval, fill, and copy nodes must declare at least one assignee.
|
|
82
|
-
|
|
83
|
-
If this happens after using a preset, check for this specific mistake first:
|
|
84
|
-
|
|
85
|
-
- the preset created `approve_1` or `fill_1`
|
|
86
|
-
- your patch created a different node id instead of patching that preset node
|
|
87
|
-
- the original preset node remained in the graph without assignees
|
|
88
|
-
|
|
89
|
-
Preferred fix order:
|
|
90
|
-
|
|
91
|
-
1. `role_search`
|
|
92
|
-
2. `member_search` only if the user explicitly named members
|
|
93
|
-
3. `role_create` if the business needs a reusable role
|
|
94
|
-
4. patch the preset node id itself with canonical `assignees.*`
|
|
95
|
-
5. retry `app_flow_apply`
|
|
96
|
-
|
|
97
|
-
### `FLOW_DEPENDENCY_MISSING`
|
|
98
|
-
|
|
99
|
-
The workflow depends on fields that do not exist yet, usually `status`. Fix schema first.
|
|
100
|
-
|
|
101
|
-
Preferred recovery:
|
|
102
|
-
|
|
103
|
-
1. use the returned `suggested_next_call`
|
|
104
|
-
2. apply the minimal schema patch
|
|
105
|
-
3. rerun `app_get_fields`
|
|
106
|
-
4. rerun `app_flow_apply`
|
|
107
|
-
|
|
108
|
-
### `INVALID_FLOW_EDGE`
|
|
109
|
-
|
|
110
|
-
One or more transitions reference unknown nodes or create an invalid graph.
|
|
111
|
-
|
|
112
|
-
### `UNKNOWN_FLOW_FIELD`
|
|
113
|
-
|
|
114
|
-
The workflow referenced a field name that does not exist, often in:
|
|
115
|
-
|
|
116
|
-
- `permissions.editable_fields`
|
|
117
|
-
|
|
118
|
-
Call `app_get_fields` and retry with the exact field names returned by the app.
|
|
119
|
-
|
|
120
|
-
### `FLOW_NODE_TYPE_UNSUPPORTED`
|
|
121
|
-
|
|
122
|
-
The public workflow builder only supports linear flows. Remove `branch` and `condition` nodes and redesign the flow with stable sequential nodes instead of retrying the same graph.
|
|
123
|
-
|
|
124
|
-
### `STATUS_FIELD_REQUIRED`
|
|
125
|
-
|
|
126
|
-
The app has no explicit status field recognized by the internal workflow compiler. Add one with `app_schema_apply`, then retry.
|
|
127
|
-
|
|
128
|
-
### `FLOW_STAGE_CONTEXT_MISSING`
|
|
129
|
-
|
|
130
|
-
Internal flow stage context was missing or invalid. Re-run `app_flow_apply` with the normalized arguments, and do not switch to hidden `solution_*` tools.
|
|
131
|
-
|
|
132
|
-
### `VALIDATION_ERROR`
|
|
133
|
-
|
|
134
|
-
Do not keep guessing preset names or node shapes. First:
|
|
135
|
-
|
|
136
|
-
1. inspect `suggested_next_call`
|
|
137
|
-
2. reuse `canonical_arguments` if present
|
|
138
|
-
3. check `allowed_values`
|
|
139
|
-
4. retry with canonical preset or canonical node types
|
|
140
|
-
5. for workflow actors and permissions, always convert to:
|
|
141
|
-
- `assignees.role_names`
|
|
142
|
-
- `assignees.member_names`
|
|
143
|
-
- `permissions.editable_fields`
|
|
144
|
-
|
|
145
|
-
Do not copy internal keys from old plan outputs or logs, including:
|
|
146
|
-
|
|
147
|
-
- `role_entries`
|
|
148
|
-
- `editable_que_ids`
|
|
149
|
-
|
|
150
|
-
## Notes
|
|
151
|
-
|
|
152
|
-
- `mode=replace` is the only supported flow apply mode
|
|
153
|
-
- `app_flow_apply` publishes by default
|
|
154
|
-
- Prefer roles over explicit members unless the user explicitly asks for named members
|
|
155
|
-
- `basic_approval` and `basic_fill_then_approve` are skeletons, not complete business workflows
|
|
156
|
-
- Report results precisely:
|
|
157
|
-
- “基础流程骨架已创建” when only the preset landed
|
|
158
|
-
- “业务定制规则已补齐” only after the patch phase is complete
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# Update Layout
|
|
2
|
-
|
|
3
|
-
Use this when fields already exist and the task is only about form grouping or ordering.
|
|
4
|
-
|
|
5
|
-
## Minimal sequence
|
|
6
|
-
|
|
7
|
-
1. `app_get_fields`
|
|
8
|
-
2. `app_get_layout`
|
|
9
|
-
3. `builder_tool_contract` when the section shape is not already obvious
|
|
10
|
-
4. `app_layout_apply`
|
|
11
|
-
|
|
12
|
-
## Example
|
|
13
|
-
|
|
14
|
-
Apply a custom layout with the canonical public section shape:
|
|
15
|
-
|
|
16
|
-
```json
|
|
17
|
-
{
|
|
18
|
-
"tool_name": "app_layout_apply",
|
|
19
|
-
"arguments": {
|
|
20
|
-
"profile": "default",
|
|
21
|
-
"app_key": "APP_123",
|
|
22
|
-
"mode": "merge",
|
|
23
|
-
"publish": true,
|
|
24
|
-
"sections": [
|
|
25
|
-
{
|
|
26
|
-
"title": "基础信息",
|
|
27
|
-
"rows": [
|
|
28
|
-
["客户名称", "订单金额"],
|
|
29
|
-
["状态", "跟进日期"]
|
|
30
|
-
]
|
|
31
|
-
}
|
|
32
|
-
]
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Common failures
|
|
38
|
-
|
|
39
|
-
### `UNKNOWN_LAYOUT_FIELD`
|
|
40
|
-
|
|
41
|
-
At least one field name does not exist. Re-read with `app_get_fields`.
|
|
42
|
-
|
|
43
|
-
### `DUPLICATE_LAYOUT_FIELD`
|
|
44
|
-
|
|
45
|
-
The same field appears more than once in the requested layout.
|
|
46
|
-
|
|
47
|
-
### `INCOMPLETE_LAYOUT`
|
|
48
|
-
|
|
49
|
-
Only happens in `mode=replace`. Switch to `mode=merge` unless you intend to place every field exactly once.
|
|
50
|
-
|
|
51
|
-
### `LAYOUT_APPLY_FAILED`
|
|
52
|
-
|
|
53
|
-
Re-read with `app_get_layout`. Check `current_field_names`, `request_id`, and `suggested_next_call`.
|
|
54
|
-
|
|
55
|
-
### `VALIDATION_ERROR`
|
|
56
|
-
|
|
57
|
-
Do not keep guessing section keys. Reuse `suggested_next_call`, `canonical_arguments`, `section_allowed_keys`, and `minimal_section_example`.
|
|
58
|
-
|
|
59
|
-
If the same shape error repeats twice, stop free-form retries and re-read `builder_tool_contract(app_layout_apply)`.
|
|
60
|
-
|
|
61
|
-
## Notes
|
|
62
|
-
|
|
63
|
-
- `section_id` is optional; it is generated from the section title
|
|
64
|
-
- `merge` is safer than `replace`
|
|
65
|
-
- Unmentioned fields stay in place or get auto-added to `未分组字段`
|
|
66
|
-
- Public builder layout sections use `title + rows`
|
|
67
|
-
- Do not treat “一行四个字段 / 四列布局 / 每行放四个” as a top-level `columns` parameter; translate it into a `rows` matrix
|
|
68
|
-
- Do not prefer `fields` or `field_ids` once `rows` is known, even though MCP may normalize those shorthands for recovery
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
# Update Schema
|
|
2
|
-
|
|
3
|
-
Use this when the app already exists and the task is only about fields.
|
|
4
|
-
|
|
5
|
-
## Minimal sequence
|
|
6
|
-
|
|
7
|
-
1. `app_resolve`
|
|
8
|
-
2. `app_get_fields`
|
|
9
|
-
3. `app_schema_apply`
|
|
10
|
-
|
|
11
|
-
## Example
|
|
12
|
-
|
|
13
|
-
Do not add platform system fields as form controls: `数据ID`, `编号`, `申请人`, `申请时间`, `创建人`, `创建时间`, `提交人`, `提交时间`, `更新时间`, `更新人`, `当前流程状态`, `当前处理人`, `当前处理节点`, `流程标题`. They are generated by Qingflow; use readback/list fields when you need them.
|
|
14
|
-
|
|
15
|
-
Read current fields first:
|
|
16
|
-
|
|
17
|
-
```json
|
|
18
|
-
{
|
|
19
|
-
"tool_name": "app_get_fields",
|
|
20
|
-
"arguments": {
|
|
21
|
-
"profile": "default",
|
|
22
|
-
"app_key": "APP_123"
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Apply the patch:
|
|
28
|
-
|
|
29
|
-
```json
|
|
30
|
-
{
|
|
31
|
-
"tool_name": "app_schema_apply",
|
|
32
|
-
"arguments": {
|
|
33
|
-
"profile": "default",
|
|
34
|
-
"app_key": "APP_123",
|
|
35
|
-
"publish": true,
|
|
36
|
-
"add_fields": [
|
|
37
|
-
{"name": "跟进日期", "type": "date"},
|
|
38
|
-
{"name": "数据封面", "type": "attachment", "as_data_cover": true}
|
|
39
|
-
],
|
|
40
|
-
"update_fields": [
|
|
41
|
-
{"selector": {"name": "金额"}, "set": {"name": "订单金额", "required": true}},
|
|
42
|
-
{"selector": {"name": "客户名称"}, "set": {"as_data_title": true}}
|
|
43
|
-
],
|
|
44
|
-
"remove_fields": [
|
|
45
|
-
{"name": "旧字段"}
|
|
46
|
-
]
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Common failures
|
|
52
|
-
|
|
53
|
-
### `FIELD_NOT_FOUND`
|
|
54
|
-
|
|
55
|
-
The selector did not match current schema. Re-read with `app_get_fields` and use `name`, `field_id`, or `que_id`.
|
|
56
|
-
|
|
57
|
-
### `DUPLICATE_FIELD`
|
|
58
|
-
|
|
59
|
-
The field already exists with a different shape. Switch from `add_fields` to `update_fields`.
|
|
60
|
-
|
|
61
|
-
### `SCHEMA_APPLY_FAILED`
|
|
62
|
-
|
|
63
|
-
Treat it as uncertain write state. Read back with `app_get_fields` before retrying.
|
|
64
|
-
|
|
65
|
-
## Notes
|
|
66
|
-
|
|
67
|
-
- `title` and `label` are accepted aliases for `name`
|
|
68
|
-
- `textarea -> long_text`
|
|
69
|
-
- `currency -> amount`
|
|
70
|
-
- `mobile -> phone`
|
|
71
|
-
- `select/radio -> single_select`
|
|
72
|
-
- `checkbox -> multi_select`
|
|
73
|
-
- `as_data_title: true` marks the app data title; the final form must have exactly one top-level data title field
|
|
74
|
-
- `as_data_cover: true` marks the app data cover; the cover is optional and must be a top-level `attachment` field
|
|
75
|
-
- `数据ID`, `编号`, applicant/creation/update time, and workflow status fields are system-generated and must not appear in `add_fields`
|
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
# Update Views
|
|
2
|
-
|
|
3
|
-
Use this when the task is only about table, card, board, or gantt views.
|
|
4
|
-
|
|
5
|
-
## Minimal sequence
|
|
6
|
-
|
|
7
|
-
1. `builder_tool_contract(tool_name="app_views_apply")`
|
|
8
|
-
2. `app_get_fields`
|
|
9
|
-
3. `app_get` for current view/chart/button inventory and app-level associated resource ids
|
|
10
|
-
4. `app_views_apply`
|
|
11
|
-
5. Use `app_associated_resources_apply` if the task includes associated reports/views
|
|
12
|
-
6. `app_get` or `view_get` again whenever apply returns `failed` or `partial_success`
|
|
13
|
-
|
|
14
|
-
If you are unsure about keys or view types, call `builder_tool_contract(tool_name="app_views_apply")` before guessing.
|
|
15
|
-
|
|
16
|
-
Important verification rule:
|
|
17
|
-
|
|
18
|
-
- `app_views_apply` can create a view object before every filter is fully verified in readback
|
|
19
|
-
- Do not report “筛选已成功应用” unless the apply result also shows `verification.views_verified=true` and `verification.view_filters_verified=true`
|
|
20
|
-
- Do not report “查询条件已成功配置” unless the apply result also shows `verification.view_query_conditions_verified=true`
|
|
21
|
-
- Do not report “关联资源已成功配置” unless `app_associated_resources_apply` shows `verification.associated_resource_view_configs_verified=true`
|
|
22
|
-
- If apply returns `partial_success`, inspect `verification.by_view`, `details.filter_mismatches`, `details.query_condition_mismatches`, and `details.associated_resource_mismatches` before claiming filters/query conditions/associated resources are active
|
|
23
|
-
|
|
24
|
-
## Example
|
|
25
|
-
|
|
26
|
-
Canonical rules before any example:
|
|
27
|
-
|
|
28
|
-
- Always use `columns`
|
|
29
|
-
- Do not emit `column_names`
|
|
30
|
-
- Treat `fields` only as a legacy alias the MCP may normalize, not as the preferred shape
|
|
31
|
-
- Use `filters` with the unified fixed-filter DSL: `field_name`, `operator`, `value`/`values`; do not write raw `judgeType` / `judgeValues`
|
|
32
|
-
- Use `query_conditions` for the frontend query panel. Do not put query-panel fields into `filters`.
|
|
33
|
-
- Do not create views named `全部数据`, `我的数据`, `我发起的`, `待办`, `已办`, or `抄送`. These are built-in default/system views. New views must use business-specific names such as `订单台账视图`, `客户跟进视图`, or `逾期任务看板`.
|
|
34
|
-
- To change a built-in default/system view, first read the existing raw `view_key` from `app_get.views` or `app_get_views`, then use `patch_views` or a full `upsert_views` item with that `view_key`.
|
|
35
|
-
- New views created by `app_views_apply` default the frontend associated report/view area to visible with `limit_type="all"`. Existing views preserve their current associated-resource display unless `associated_resources` is explicitly patched.
|
|
36
|
-
- Use `app_associated_resources_apply` for the associated report/view resource pool, selected resources, and match rules. Permission is split like the backend: resource pool writes use EditAppAuth, while `view_configs` uses the view config/DataManageAuth path. `associated_item_id` is the internal associated-resource id from `app_get.associated_resources`; `view_configs`, remove, and reorder may also pass an existing resource's `chart_id`/`chart_key`/`view_key`, which the tool resolves to the internal id. Do not write backend raw `sourceType`; reports default to BI app reports, and dataset reports use `report_source="dataset"`. Use `match_mappings` with `target_field + operator + source_field/value` for associated view/report filters; read `match-rules.md` if field type compatibility is unclear.
|
|
37
|
-
- For gantt, use `start_field`, `end_field`, and optionally `title_field`
|
|
38
|
-
- If `app_get.views` or `app_get_views` shows duplicate view names, include `view_key` in `upsert_views[]` and update that exact target
|
|
39
|
-
- Builder view writes always use the raw `view_key` from `app_get.views[].view_key`, such as `emsrao25rs02`. Do not pass `custom:emsrao25rs02`; that prefixed form is only for record-data `view_id`.
|
|
40
|
-
- For an existing view, prefer `patch_views` for parameter replacement. Do not send a partial `upsert_views` object such as only `name/type/query_conditions`; backend view saves require other type-specific fields, and the patch path preserves them for you.
|
|
41
|
-
|
|
42
|
-
Apply a business table view:
|
|
43
|
-
|
|
44
|
-
```json
|
|
45
|
-
{
|
|
46
|
-
"tool_name": "app_views_apply",
|
|
47
|
-
"arguments": {
|
|
48
|
-
"profile": "default",
|
|
49
|
-
"app_key": "APP_123",
|
|
50
|
-
"publish": true,
|
|
51
|
-
"upsert_views": [
|
|
52
|
-
{
|
|
53
|
-
"name": "订单台账视图",
|
|
54
|
-
"view_key": "VIEW_KEY_IF_DUPLICATE_NAMES_EXIST",
|
|
55
|
-
"type": "table",
|
|
56
|
-
"columns": ["订单编号", "客户名称", "订单金额", "状态"]
|
|
57
|
-
}
|
|
58
|
-
],
|
|
59
|
-
"remove_views": []
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
```
|
|
63
|
-
After `app_views_apply` returns canonical arguments or blocking issues, prefer reusing its `suggested_next_call.arguments` directly. Do not rewrite aliases back into non-canonical keys such as `column_names`.
|
|
64
|
-
|
|
65
|
-
Existing table view: replace only frontend query conditions:
|
|
66
|
-
|
|
67
|
-
```json
|
|
68
|
-
{
|
|
69
|
-
"tool_name": "app_views_apply",
|
|
70
|
-
"arguments": {
|
|
71
|
-
"profile": "default",
|
|
72
|
-
"app_key": "APP_123",
|
|
73
|
-
"publish": true,
|
|
74
|
-
"patch_views": [
|
|
75
|
-
{
|
|
76
|
-
"view_key": "VIEW_KEY",
|
|
77
|
-
"set": {
|
|
78
|
-
"query_conditions": {
|
|
79
|
-
"enabled": true,
|
|
80
|
-
"exact": false,
|
|
81
|
-
"hide_before_query": false,
|
|
82
|
-
"rows": [["客户名称", "负责人"], ["创建时间"]]
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
],
|
|
87
|
-
"remove_views": []
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
Meaning:
|
|
93
|
-
|
|
94
|
-
- `filters` are saved view filters and apply immediately when the view opens.
|
|
95
|
-
- `query_conditions` only configures which fields appear in the frontend query panel. The query values come later from the user through the page.
|
|
96
|
-
- `query_conditions.rows` is a matrix of field names and is compiled to backend `queryCondition` field ids.
|
|
97
|
-
- The patch call preserves the view's existing columns, saved filters, type-specific date/card/board config, buttons, visibility, and other backend-required fields.
|
|
98
|
-
|
|
99
|
-
View associated resources example:
|
|
100
|
-
|
|
101
|
-
```json
|
|
102
|
-
{
|
|
103
|
-
"tool_name": "app_associated_resources_apply",
|
|
104
|
-
"arguments": {
|
|
105
|
-
"profile": "default",
|
|
106
|
-
"app_key": "APP_123",
|
|
107
|
-
"upsert_resources": [],
|
|
108
|
-
"remove_associated_item_ids": [],
|
|
109
|
-
"reorder_associated_item_ids": [],
|
|
110
|
-
"view_configs": [
|
|
111
|
-
{
|
|
112
|
-
"view_key": "VIEW_KEY",
|
|
113
|
-
"visible": true,
|
|
114
|
-
"limit_type": "select",
|
|
115
|
-
"associated_item_ids": [123, 124]
|
|
116
|
-
}
|
|
117
|
-
]
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
Use `{"visible": true, "limit_type": "all"}` to show all app-level associated resources, and `{"visible": false}` to hide the area. The ids above can be internal `associated_item_id` values or existing resource `chart_id`/`chart_key`/`view_key` values from `app_get.associated_resources`. Before creating a resource, check whether the same `target_app_key + view_key/chart_key` already exists; if it does, use `patch_resources` with that `associated_item_id`. Dataset BI reports must already exist in QingBI and should be attached with `report_source="dataset"`; do not try to create them through `app_charts_apply`. If you create a new associated item in the same call, give it a `client_key` and reference it from `view_configs[].associated_item_refs`; `client_key` is not persisted and cannot deduplicate a later call.
|
|
123
|
-
|
|
124
|
-
Create and show a BI indicator-card report in the same call:
|
|
125
|
-
|
|
126
|
-
```json
|
|
127
|
-
{
|
|
128
|
-
"tool_name": "app_associated_resources_apply",
|
|
129
|
-
"arguments": {
|
|
130
|
-
"profile": "default",
|
|
131
|
-
"app_key": "APP_123",
|
|
132
|
-
"upsert_resources": [
|
|
133
|
-
{
|
|
134
|
-
"client_key": "total_hours_card",
|
|
135
|
-
"graph_type": "chart",
|
|
136
|
-
"target_app_key": "TIMESHEET_APP",
|
|
137
|
-
"chart_key": "CHART_KEY",
|
|
138
|
-
"report_source": "app",
|
|
139
|
-
"match_mappings": [
|
|
140
|
-
{"target_field": "关联员工", "source_field": "数据ID"},
|
|
141
|
-
{"target_field": "状态", "value": "待提交"}
|
|
142
|
-
]
|
|
143
|
-
}
|
|
144
|
-
],
|
|
145
|
-
"remove_associated_item_ids": [],
|
|
146
|
-
"reorder_associated_item_ids": [],
|
|
147
|
-
"view_configs": [
|
|
148
|
-
{
|
|
149
|
-
"view_key": "VIEW_KEY",
|
|
150
|
-
"visible": true,
|
|
151
|
-
"limit_type": "select",
|
|
152
|
-
"associated_item_refs": ["total_hours_card"]
|
|
153
|
-
}
|
|
154
|
-
]
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
Board example:
|
|
160
|
-
|
|
161
|
-
```json
|
|
162
|
-
{
|
|
163
|
-
"tool_name": "app_views_apply",
|
|
164
|
-
"arguments": {
|
|
165
|
-
"profile": "default",
|
|
166
|
-
"app_key": "APP_123",
|
|
167
|
-
"upsert_views": [
|
|
168
|
-
{
|
|
169
|
-
"name": "按状态看板",
|
|
170
|
-
"type": "board",
|
|
171
|
-
"group_by": "状态",
|
|
172
|
-
"columns": ["订单编号", "客户名称", "订单金额"]
|
|
173
|
-
}
|
|
174
|
-
],
|
|
175
|
-
"remove_views": []
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
Gantt example with filters:
|
|
181
|
-
|
|
182
|
-
```json
|
|
183
|
-
{
|
|
184
|
-
"tool_name": "app_views_apply",
|
|
185
|
-
"arguments": {
|
|
186
|
-
"profile": "default",
|
|
187
|
-
"app_key": "APP_123",
|
|
188
|
-
"upsert_views": [
|
|
189
|
-
{
|
|
190
|
-
"name": "项目甘特图",
|
|
191
|
-
"type": "gantt",
|
|
192
|
-
"columns": ["项目名称", "开始日期", "结束日期", "状态"],
|
|
193
|
-
"start_field": "开始日期",
|
|
194
|
-
"end_field": "结束日期",
|
|
195
|
-
"title_field": "项目名称",
|
|
196
|
-
"filters": [
|
|
197
|
-
{
|
|
198
|
-
"field_name": "状态",
|
|
199
|
-
"operator": "eq",
|
|
200
|
-
"value": "进行中"
|
|
201
|
-
}
|
|
202
|
-
]
|
|
203
|
-
}
|
|
204
|
-
],
|
|
205
|
-
"remove_views": []
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
## Common failures
|
|
211
|
-
|
|
212
|
-
### `UNKNOWN_VIEW_FIELD`
|
|
213
|
-
|
|
214
|
-
At least one `columns` or `group_by` field name does not exist.
|
|
215
|
-
|
|
216
|
-
### `INVALID_VIEW_TYPE`
|
|
217
|
-
|
|
218
|
-
Public view types are only `table`, `card`, `board`, `gantt`.
|
|
219
|
-
|
|
220
|
-
Map old or intuitive labels before calling the tool:
|
|
221
|
-
|
|
222
|
-
- `tableView` -> `table`
|
|
223
|
-
- `cardView` -> `card`
|
|
224
|
-
- `kanban` -> `board`
|
|
225
|
-
|
|
226
|
-
### `INVALID_GANTT_CONFIG`
|
|
227
|
-
|
|
228
|
-
Gantt views require at least:
|
|
229
|
-
|
|
230
|
-
- `start_field`
|
|
231
|
-
- `end_field`
|
|
232
|
-
|
|
233
|
-
Also make sure these field names already exist on the app.
|
|
234
|
-
|
|
235
|
-
### `VIEW_APPLY_FAILED`
|
|
236
|
-
|
|
237
|
-
The backend rejected the normalized view payload. Re-read fields and inspect `request_id` before retrying.
|
|
238
|
-
|
|
239
|
-
Do not repeat `app_views_apply` with guessed keys. First:
|
|
240
|
-
|
|
241
|
-
1. check `suggested_next_call`
|
|
242
|
-
2. reuse `canonical_arguments` if present
|
|
243
|
-
3. call `app_get_views` to see whether any requested views landed anyway
|
|
244
|
-
4. if needed, call `builder_tool_contract`
|
|
245
|
-
5. retry only the minimal failed view patch
|
|
246
|
-
|
|
247
|
-
### `VIEW_FILTER_READBACK_MISMATCH`
|
|
248
|
-
|
|
249
|
-
The view object was created or updated, but the readback config did not keep the intended filter values.
|
|
250
|
-
|
|
251
|
-
Treat this as:
|
|
252
|
-
|
|
253
|
-
- the view exists
|
|
254
|
-
- the filter is **not yet verified**
|
|
255
|
-
|
|
256
|
-
Do not tell the user the filter is active until the readback verification matches the intended filter.
|
|
257
|
-
|
|
258
|
-
### `VIEW_QUERY_CONDITION_READBACK_MISMATCH`
|
|
259
|
-
|
|
260
|
-
The view object was created or updated, but the readback config did not keep the intended frontend query-condition settings.
|
|
261
|
-
|
|
262
|
-
Treat this as:
|
|
263
|
-
|
|
264
|
-
- the view exists
|
|
265
|
-
- the query panel configuration is **not yet verified**
|
|
266
|
-
|
|
267
|
-
Do not tell the user the query condition is active until readback matches the intended `query_conditions`.
|
|
268
|
-
|
|
269
|
-
### `QUERY_CONDITION_FIELD_NOT_FOUND`
|
|
270
|
-
|
|
271
|
-
At least one `query_conditions.rows` field does not exist on the app.
|
|
272
|
-
|
|
273
|
-
### `INVALID_QUERY_CONDITION_FIELD`
|
|
274
|
-
|
|
275
|
-
The field exists but cannot be used in the frontend query-condition panel, such as attachment, relation, Q-Linker, code block, location/address, or subtable/subfield selections.
|
|
276
|
-
|
|
277
|
-
## Notes
|
|
278
|
-
|
|
279
|
-
- `fields` is accepted as an alias for `columns`, but skill examples should still use `columns`
|
|
280
|
-
- `column_names` should not appear in skill examples
|
|
281
|
-
- `app_get_views` should be treated as canonical readback and now returns `columns`
|
|
282
|
-
- If `app_views_apply` returns `AMBIGUOUS_VIEW`, stop and re-run `app_get_views`; then retry with the exact `view_key`
|
|
283
|
-
- `filters` are ANDed together as one flat condition group
|
|
284
|
-
- `query_conditions.rows` does not mean OR; it controls frontend query-field layout
|
|
285
|
-
- `app_views_apply` publishes by default
|
|
286
|
-
- For select-style filters, success means the backend preserved the option value in readback, not just that the view name now exists
|