@josephyan/qingflow-app-builder-mcp 0.2.0-beta.71 → 0.2.0-beta.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/skills/qingflow-app-builder/SKILL.md +21 -22
- package/skills/qingflow-app-builder/references/create-app.md +1 -1
- package/skills/qingflow-app-builder/references/flow-actors-and-permissions.md +3 -3
- package/skills/qingflow-app-builder/references/gotchas.md +5 -5
- package/skills/qingflow-app-builder/references/solution-playbooks.md +11 -11
- package/skills/qingflow-app-builder/references/tool-selection.md +13 -13
- package/skills/qingflow-app-builder/references/update-flow.md +5 -5
- package/skills/qingflow-app-builder/references/update-layout.md +4 -4
- package/skills/qingflow-app-builder/references/update-schema.md +4 -4
- package/skills/qingflow-app-builder/references/update-views.md +7 -7
- package/src/qingflow_mcp/backend_client.py +1 -0
- package/src/qingflow_mcp/builder_facade/models.py +22 -11
- package/src/qingflow_mcp/builder_facade/service.py +183 -121
- package/src/qingflow_mcp/cli/commands/__init__.py +4 -1
- package/src/qingflow_mcp/cli/commands/builder.py +81 -64
- package/src/qingflow_mcp/cli/commands/chart.py +18 -0
- package/src/qingflow_mcp/cli/commands/portal.py +25 -0
- package/src/qingflow_mcp/cli/commands/view.py +18 -0
- package/src/qingflow_mcp/cli/context.py +9 -0
- package/src/qingflow_mcp/response_trim.py +219 -178
- package/src/qingflow_mcp/server_app_builder.py +18 -42
- package/src/qingflow_mcp/server_app_user.py +21 -1
- package/src/qingflow_mcp/tools/ai_builder_tools.py +244 -124
- package/src/qingflow_mcp/tools/app_tools.py +0 -4
- package/src/qingflow_mcp/tools/resource_read_tools.py +399 -0
package/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Install:
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npm install @josephyan/qingflow-app-builder-mcp@0.2.0-beta.
|
|
6
|
+
npm install @josephyan/qingflow-app-builder-mcp@0.2.0-beta.73
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Run:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx -y -p @josephyan/qingflow-app-builder-mcp@0.2.0-beta.
|
|
12
|
+
npx -y -p @josephyan/qingflow-app-builder-mcp@0.2.0-beta.73 qingflow-app-builder-mcp
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Environment:
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -48,7 +48,7 @@ Default modeling rules:
|
|
|
48
48
|
|
|
49
49
|
- Authentication and workspace: `auth_*`, `workspace_*`
|
|
50
50
|
- File upload: `file_upload_local`
|
|
51
|
-
- Resource resolve/read: `package_list`, `package_resolve`, `package_create`, `builder_tool_contract`, `member_search`, `role_search`, `app_resolve`, `
|
|
51
|
+
- Resource resolve/read: `package_list`, `package_resolve`, `package_create`, `builder_tool_contract`, `member_search`, `role_search`, `app_resolve`, `app_get`, `app_get_fields`, `app_get_layout`, `app_get_views`, `app_get_flow`, `app_get_charts`, `portal_list`, `portal_get`, `view_get`, `chart_get`
|
|
52
52
|
- Resource patch: `app_schema_apply`, `app_layout_apply`, `app_flow_apply`, `app_views_apply`, `app_charts_apply`, `portal_apply`, `package_attach_app`, `app_release_edit_lock_if_mine`, `role_create`
|
|
53
53
|
- Publish and verify: `app_publish_verify`
|
|
54
54
|
|
|
@@ -59,11 +59,10 @@ Note:
|
|
|
59
59
|
- `app_schema_apply` / `app_layout_apply` / `app_flow_apply` / `app_views_apply` publish by default; pass `publish=false` only when you intentionally want to leave changes in draft.
|
|
60
60
|
- `app_charts_apply` is immediate-live and does not publish; it resolves targets by `chart_id` first and then exact unique chart name.
|
|
61
61
|
- `portal_apply` uses replace semantics for sections; remove a section by omitting it from the next full sections list. `publish=false` only guarantees draft/base-info updates, and `chart_ref/view_ref` resolve by `id/key` first and exact unique name second.
|
|
62
|
-
- `
|
|
63
|
-
- `chart_get` returns one chart's base info
|
|
62
|
+
- `app_get_charts` is the compact discovery path for current chart inventory; use it before `app_charts_apply` when you need exact `chart_id` values.
|
|
63
|
+
- `chart_get` returns one chart's base info and config only; public builder flows should treat data reads as user-side access, not builder config access.
|
|
64
64
|
- `portal_list` is the discovery path for accessible portals.
|
|
65
|
-
- `
|
|
66
|
-
- `portal_get` returns portal-level detail plus a component inventory; it does not inline chart/view detail.
|
|
65
|
+
- `portal_get` returns portal-level config detail plus a component inventory; it does not inline chart/view detail or user-side chart/view data.
|
|
67
66
|
- `view_get` returns one view's definition detail only; use `record_list` separately when you need rows from that view.
|
|
68
67
|
- `app_schema_apply` / `app_layout_apply` / `app_flow_apply` / `app_views_apply` now perform planning, normalization, and dependency checks internally; when prechecks block, read the returned blocking issues and `suggested_next_call` directly from the apply result.
|
|
69
68
|
- If you are unsure about a public builder tool's keys, aliases, presets, or minimal legal shape, call `builder_tool_contract` instead of guessing.
|
|
@@ -108,7 +107,7 @@ For builder work:
|
|
|
108
107
|
- one app: continue with `app_resolve`
|
|
109
108
|
- multi-app package/system: create or resolve the package, then create each app separately before adding relations
|
|
110
109
|
3. Resolve the target app with `app_resolve` if the request is an update. Use exactly one selector mode: `app_key`, or `app_name + package_tag_id`.
|
|
111
|
-
4. Read only the smallest
|
|
110
|
+
4. Read only the smallest config slice you need: `app_get`, `app_get_fields`, `app_get_layout`, `app_get_views`, `app_get_flow`, `app_get_charts`, `portal_get`.
|
|
112
111
|
5. Use `app_schema_apply` for create/upsert/remove field work. It publishes by default after the patch lands; noop schema requests do not publish.
|
|
113
112
|
6. If the app must belong to a package, use `package_attach_app` explicitly after schema work with `tag_id + app_key` unless readback already shows the target `tag_id`.
|
|
114
113
|
7. Use `app_layout_apply` only when the user is explicitly changing layout. Prefer the default `mode=merge`; use `mode=replace` only when you intend to place every field explicitly. It publishes by default after the patch lands; noop layout requests do not publish.
|
|
@@ -120,16 +119,16 @@ For builder work:
|
|
|
120
119
|
For view work, keep the order strict:
|
|
121
120
|
|
|
122
121
|
1. `builder_tool_contract`
|
|
123
|
-
2. `
|
|
124
|
-
3. `
|
|
122
|
+
2. `app_get_fields`
|
|
123
|
+
3. `app_get_views`
|
|
125
124
|
4. `app_views_apply`
|
|
126
|
-
5. `
|
|
125
|
+
5. `app_get_views` again whenever `app_views_apply` returns `failed` or `partial_success`
|
|
127
126
|
|
|
128
127
|
For flow work, keep the order strict:
|
|
129
128
|
|
|
130
129
|
1. `builder_tool_contract`
|
|
131
|
-
2. `
|
|
132
|
-
3. `
|
|
130
|
+
2. `app_get_fields`
|
|
131
|
+
3. `app_get_flow`
|
|
133
132
|
4. `role_search` or `member_search` if assignees need to come from the directory
|
|
134
133
|
5. `role_create` if the user wants a reusable role and no suitable role exists yet
|
|
135
134
|
6. Start from a canonical preset when possible
|
|
@@ -143,10 +142,10 @@ For flow work, keep the order strict:
|
|
|
143
142
|
- support `assignees.member_names` / `assignees.member_emails` / `assignees.member_uids`
|
|
144
143
|
10. When a node must edit specific fields, declare `permissions.editable_fields`
|
|
145
144
|
11. `app_flow_apply`
|
|
146
|
-
12. `
|
|
147
|
-
13. Use `
|
|
145
|
+
12. `app_get_flow` after apply whenever the user asked for verification or apply returns `partial_success`
|
|
146
|
+
13. Use `app_get_charts` before chart work whenever exact current `chart_id` values matter
|
|
148
147
|
14. Use `app_charts_apply` for QingBI chart creation and updates, not raw `qingbi_report_*` writes
|
|
149
|
-
15. Use `
|
|
148
|
+
15. Use `portal_get` before portal work whenever exact current portal config and section inventory matter
|
|
150
149
|
16. Use `portal_apply` for builder-side portal work; treat sections as a full replacement list
|
|
151
150
|
|
|
152
151
|
For additive work on existing systems:
|
|
@@ -201,7 +200,7 @@ For additive work on existing systems:
|
|
|
201
200
|
- Treat post-write readback as the source of truth, not just write status codes
|
|
202
201
|
- For views, a top-level `VIEW_APPLY_FAILED` does not prove all requested views failed. Read back the view list and verify which views actually landed.
|
|
203
202
|
- For views, “view exists” is not the same as “filters are active”. If `app_views_apply` returns `partial_success`, `views_verified=false`, or `details.filter_mismatches`, report the view as created but the filters as unverified until readback confirms them.
|
|
204
|
-
- If multiple views share the same name, do not guess which one to update. Read `view_key` from `
|
|
203
|
+
- If multiple views share the same name, do not guess which one to update. Read `view_key` from `app_get_views` and pass it explicitly in `upsert_views[]`.
|
|
205
204
|
- In final user-facing summaries, distinguish clearly between:
|
|
206
205
|
- contract is visible / canonical shape is known
|
|
207
206
|
- apply precheck succeeded
|
|
@@ -218,13 +217,13 @@ For additive work on existing systems:
|
|
|
218
217
|
- Create one package: `package_create`
|
|
219
218
|
- Read one public tool contract: `builder_tool_contract`
|
|
220
219
|
- Resolve one app: `app_resolve`
|
|
221
|
-
- Read one app summary: `
|
|
222
|
-
- Read fields only: `
|
|
223
|
-
- Read layout summary: `
|
|
224
|
-
- Read views summary: `
|
|
225
|
-
- Read flow summary: `
|
|
226
|
-
- Read chart summary: `
|
|
227
|
-
- Read portal
|
|
220
|
+
- Read one app summary: `app_get`
|
|
221
|
+
- Read fields only: `app_get_fields`
|
|
222
|
+
- Read layout summary: `app_get_layout`
|
|
223
|
+
- Read views summary: `app_get_views`
|
|
224
|
+
- Read flow summary: `app_get_flow`
|
|
225
|
+
- Read chart summary: `app_get_charts`
|
|
226
|
+
- Read portal config: `portal_get`
|
|
228
227
|
- Search members for workflow assignees: `member_search`
|
|
229
228
|
- Search roles for workflow assignees: `role_search`
|
|
230
229
|
- Create reusable workflow role: `role_create`
|
|
@@ -117,7 +117,7 @@ The create route did not resolve in the current backend route context. Re-run `w
|
|
|
117
117
|
|
|
118
118
|
### `PACKAGE_ATTACH_FAILED`
|
|
119
119
|
|
|
120
|
-
Do not retry schema creation. Re-run only `package_attach_app`, then verify with `
|
|
120
|
+
Do not retry schema creation. Re-run only `package_attach_app`, then verify with `app_get`.
|
|
121
121
|
|
|
122
122
|
### Hierarchy modeling mistake
|
|
123
123
|
|
|
@@ -17,8 +17,8 @@ Use this when the workflow needs real assignees or node-level editable field per
|
|
|
17
17
|
|
|
18
18
|
## Recommended order
|
|
19
19
|
|
|
20
|
-
1. `
|
|
21
|
-
2. `
|
|
20
|
+
1. `app_get_fields`
|
|
21
|
+
2. `app_get_flow`
|
|
22
22
|
3. `role_search`
|
|
23
23
|
4. `member_search` when the user explicitly names people
|
|
24
24
|
5. `role_create` when no reusable role exists and the user wants role-based routing
|
|
@@ -119,5 +119,5 @@ Use this when the workflow needs real assignees or node-level editable field per
|
|
|
119
119
|
|
|
120
120
|
### `UNKNOWN_FLOW_FIELD`
|
|
121
121
|
|
|
122
|
-
- reread fields with `
|
|
122
|
+
- reread fields with `app_get_fields`
|
|
123
123
|
- only pass real current field names to `permissions.editable_fields`
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
## Readback scope
|
|
28
28
|
|
|
29
29
|
- Prefer summary reads over large raw payloads
|
|
30
|
-
- Use `
|
|
31
|
-
- Use `
|
|
32
|
-
- Use `
|
|
33
|
-
- Use `
|
|
30
|
+
- Use `app_get_fields` before schema or view work
|
|
31
|
+
- Use `app_get_layout` before layout work
|
|
32
|
+
- Use `app_get_flow` before workflow work
|
|
33
|
+
- Use `app_get_views` before view work
|
|
34
34
|
|
|
35
35
|
## Workflow dependencies
|
|
36
36
|
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
- For flow work, do not replay internal keys from old logs or plan outputs. Public builder calls should stay on:
|
|
54
54
|
- `assignees.role_ids` / `assignees.member_uids` / `assignees.member_emails`
|
|
55
55
|
- `permissions.editable_fields`
|
|
56
|
-
- For view work, treat `columns` as the only canonical public key. `
|
|
56
|
+
- For view work, treat `columns` as the only canonical public key. `app_get_views` and `app_views_apply` should all be read and written in that shape.
|
|
57
57
|
- For layout work, treat `title + rows` as the only canonical public section shape. `fields`, `field_ids`, and `columns` may appear in legacy/internal shapes, but they are not the preferred public write shape.
|
|
58
58
|
- A created view is not enough to claim a filter succeeded. When `app_views_apply` returns `partial_success`, `views_verified=false`, or `details.filter_mismatches`, treat the view as present but the filter as unverified.
|
|
59
59
|
- If duplicate view names exist, do not retry by name. Read the exact `view_key` and target that one.
|
|
@@ -13,20 +13,20 @@ Use these when you need a quick reminder of the standard v2 builder sequences.
|
|
|
13
13
|
## Update fields on an existing app
|
|
14
14
|
|
|
15
15
|
1. `app_resolve`
|
|
16
|
-
2. `
|
|
16
|
+
2. `app_get_fields`
|
|
17
17
|
3. `app_schema_apply`
|
|
18
18
|
|
|
19
19
|
## Rework layout
|
|
20
20
|
|
|
21
|
-
1. `
|
|
21
|
+
1. `app_get_layout`
|
|
22
22
|
2. `app_layout_apply`
|
|
23
23
|
|
|
24
24
|
Prefer `mode=merge`. Use `mode=replace` only when every field placement is intentional.
|
|
25
25
|
|
|
26
26
|
## Add or update workflow
|
|
27
27
|
|
|
28
|
-
1. `
|
|
29
|
-
2. `
|
|
28
|
+
1. `app_get_fields`
|
|
29
|
+
2. `app_get_flow`
|
|
30
30
|
3. `role_search` or `member_search`
|
|
31
31
|
4. `role_create` if the business wants a reusable role and no good exact role exists
|
|
32
32
|
5. `app_flow_apply`
|
|
@@ -36,8 +36,8 @@ If it reports `FLOW_ASSIGNEE_REQUIRED`, resolve roles or members first and retry
|
|
|
36
36
|
|
|
37
37
|
## Add or update views
|
|
38
38
|
|
|
39
|
-
1. `
|
|
40
|
-
2. `
|
|
39
|
+
1. `app_get_fields`
|
|
40
|
+
2. `app_get_views`
|
|
41
41
|
3. `app_views_apply`
|
|
42
42
|
|
|
43
43
|
For both workflow and view work, prefer `suggested_next_call` over re-guessing arguments after a validation failure.
|
|
@@ -46,8 +46,8 @@ For both workflow and view work, prefer `suggested_next_call` over re-guessing a
|
|
|
46
46
|
|
|
47
47
|
Prefer these fields after writes:
|
|
48
48
|
|
|
49
|
-
- `
|
|
50
|
-
- `
|
|
51
|
-
- `
|
|
52
|
-
- `
|
|
53
|
-
- `
|
|
49
|
+
- `app_get.tag_ids`
|
|
50
|
+
- `app_get.publish_status`
|
|
51
|
+
- `app_get_layout.unplaced_fields`
|
|
52
|
+
- `app_get_views.views`
|
|
53
|
+
- `app_get_flow.nodes`
|
|
@@ -31,13 +31,13 @@ If the user asks for multiple forms/modules that relate to each other, this is a
|
|
|
31
31
|
|
|
32
32
|
## Summary reads
|
|
33
33
|
|
|
34
|
-
- `
|
|
35
|
-
- `
|
|
36
|
-
- `
|
|
37
|
-
- `
|
|
38
|
-
- `
|
|
39
|
-
- `
|
|
40
|
-
- `
|
|
34
|
+
- `app_get`: overall app config health, publish state, counts, and builder editability
|
|
35
|
+
- `app_get_fields`: field names, types, required flags, section ids
|
|
36
|
+
- `app_get_layout`: sections, rows, unplaced fields
|
|
37
|
+
- `app_get_views`: current view names, types, columns, group-by
|
|
38
|
+
- `app_get_flow`: workflow enabled state, nodes, transitions
|
|
39
|
+
- `app_get_charts`: current chart ids, names, types, order
|
|
40
|
+
- `portal_get`: current portal config detail and component inventory
|
|
41
41
|
|
|
42
42
|
## Apply tools
|
|
43
43
|
|
|
@@ -64,17 +64,17 @@ These execute normalized patches and publish by default unless `publish=false`.
|
|
|
64
64
|
- Create a brand new multi-app system/package:
|
|
65
65
|
`package_create/resolve -> per-app app_schema_apply -> package_attach_app per app -> relation field patches`
|
|
66
66
|
- Update fields on an existing app:
|
|
67
|
-
`app_resolve ->
|
|
67
|
+
`app_resolve -> app_get_fields -> app_schema_apply`
|
|
68
68
|
- Tidy layout:
|
|
69
|
-
`
|
|
69
|
+
`app_get_fields -> app_get_layout -> builder_tool_contract (if shape is unclear) -> app_layout_apply`
|
|
70
70
|
- Add workflow:
|
|
71
|
-
`builder_tool_contract ->
|
|
71
|
+
`builder_tool_contract -> app_get_fields -> app_get_flow -> role_search/member_search -> app_flow_apply -> app_get_flow`
|
|
72
72
|
- Add views:
|
|
73
|
-
`builder_tool_contract ->
|
|
73
|
+
`builder_tool_contract -> app_get_fields -> app_get_views -> app_views_apply -> app_get_views`
|
|
74
74
|
- Add QingBI charts:
|
|
75
|
-
`builder_tool_contract ->
|
|
75
|
+
`builder_tool_contract -> app_get_fields -> app_get_charts -> app_charts_apply -> app_get_charts`
|
|
76
76
|
- Create or update a portal:
|
|
77
|
-
`builder_tool_contract ->
|
|
77
|
+
`builder_tool_contract -> portal_get -> portal_apply -> portal_get`
|
|
78
78
|
|
|
79
79
|
## Avoid
|
|
80
80
|
|
|
@@ -5,8 +5,8 @@ Use this when the app already exists and the task is only about workflow.
|
|
|
5
5
|
## Minimal sequence
|
|
6
6
|
|
|
7
7
|
1. `builder_tool_contract(tool_name="app_flow_apply")`
|
|
8
|
-
2. `
|
|
9
|
-
3. `
|
|
8
|
+
2. `app_get_fields`
|
|
9
|
+
3. `app_get_flow`
|
|
10
10
|
4. `role_search` or `member_search`
|
|
11
11
|
5. `role_create` if the user wants a reusable directory role and no good role exists
|
|
12
12
|
6. start from a canonical preset when possible
|
|
@@ -17,7 +17,7 @@ Use this when the app already exists and the task is only about workflow.
|
|
|
17
17
|
Do not add a second approval/fill node with a new id unless you are intentionally replacing the skeleton.
|
|
18
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
19
|
9. `app_flow_apply`
|
|
20
|
-
10. `
|
|
20
|
+
10. `app_get_flow` when apply returns `partial_success` or the user asked for verification
|
|
21
21
|
|
|
22
22
|
If you are unsure about presets or node shapes, call `builder_tool_contract(tool_name="app_flow_apply")` before guessing.
|
|
23
23
|
|
|
@@ -102,7 +102,7 @@ Preferred recovery:
|
|
|
102
102
|
|
|
103
103
|
1. use the returned `suggested_next_call`
|
|
104
104
|
2. apply the minimal schema patch
|
|
105
|
-
3. rerun `
|
|
105
|
+
3. rerun `app_get_fields`
|
|
106
106
|
4. rerun `app_flow_apply`
|
|
107
107
|
|
|
108
108
|
### `INVALID_FLOW_EDGE`
|
|
@@ -115,7 +115,7 @@ The workflow referenced a field name that does not exist, often in:
|
|
|
115
115
|
|
|
116
116
|
- `permissions.editable_fields`
|
|
117
117
|
|
|
118
|
-
Call `
|
|
118
|
+
Call `app_get_fields` and retry with the exact field names returned by the app.
|
|
119
119
|
|
|
120
120
|
### `FLOW_NODE_TYPE_UNSUPPORTED`
|
|
121
121
|
|
|
@@ -4,8 +4,8 @@ Use this when fields already exist and the task is only about form grouping or o
|
|
|
4
4
|
|
|
5
5
|
## Minimal sequence
|
|
6
6
|
|
|
7
|
-
1. `
|
|
8
|
-
2. `
|
|
7
|
+
1. `app_get_fields`
|
|
8
|
+
2. `app_get_layout`
|
|
9
9
|
3. `builder_tool_contract` when the section shape is not already obvious
|
|
10
10
|
4. `app_layout_apply`
|
|
11
11
|
|
|
@@ -38,7 +38,7 @@ Apply a custom layout with the canonical public section shape:
|
|
|
38
38
|
|
|
39
39
|
### `UNKNOWN_LAYOUT_FIELD`
|
|
40
40
|
|
|
41
|
-
At least one field name does not exist. Re-read with `
|
|
41
|
+
At least one field name does not exist. Re-read with `app_get_fields`.
|
|
42
42
|
|
|
43
43
|
### `DUPLICATE_LAYOUT_FIELD`
|
|
44
44
|
|
|
@@ -50,7 +50,7 @@ Only happens in `mode=replace`. Switch to `mode=merge` unless you intend to plac
|
|
|
50
50
|
|
|
51
51
|
### `LAYOUT_APPLY_FAILED`
|
|
52
52
|
|
|
53
|
-
Re-read with `
|
|
53
|
+
Re-read with `app_get_layout`. Check `current_field_names`, `request_id`, and `suggested_next_call`.
|
|
54
54
|
|
|
55
55
|
### `VALIDATION_ERROR`
|
|
56
56
|
|
|
@@ -5,7 +5,7 @@ Use this when the app already exists and the task is only about fields.
|
|
|
5
5
|
## Minimal sequence
|
|
6
6
|
|
|
7
7
|
1. `app_resolve`
|
|
8
|
-
2. `
|
|
8
|
+
2. `app_get_fields`
|
|
9
9
|
3. `app_schema_apply`
|
|
10
10
|
|
|
11
11
|
## Example
|
|
@@ -14,7 +14,7 @@ Read current fields first:
|
|
|
14
14
|
|
|
15
15
|
```json
|
|
16
16
|
{
|
|
17
|
-
"tool_name": "
|
|
17
|
+
"tool_name": "app_get_fields",
|
|
18
18
|
"arguments": {
|
|
19
19
|
"profile": "default",
|
|
20
20
|
"app_key": "APP_123"
|
|
@@ -48,7 +48,7 @@ Apply the patch:
|
|
|
48
48
|
|
|
49
49
|
### `FIELD_NOT_FOUND`
|
|
50
50
|
|
|
51
|
-
The selector did not match current schema. Re-read with `
|
|
51
|
+
The selector did not match current schema. Re-read with `app_get_fields` and use `name`, `field_id`, or `que_id`.
|
|
52
52
|
|
|
53
53
|
### `DUPLICATE_FIELD`
|
|
54
54
|
|
|
@@ -56,7 +56,7 @@ The field already exists with a different shape. Switch from `add_fields` to `up
|
|
|
56
56
|
|
|
57
57
|
### `SCHEMA_APPLY_FAILED`
|
|
58
58
|
|
|
59
|
-
Treat it as uncertain write state. Read back with `
|
|
59
|
+
Treat it as uncertain write state. Read back with `app_get_fields` before retrying.
|
|
60
60
|
|
|
61
61
|
## Notes
|
|
62
62
|
|
|
@@ -5,10 +5,10 @@ Use this when the task is only about table, card, board, or gantt views.
|
|
|
5
5
|
## Minimal sequence
|
|
6
6
|
|
|
7
7
|
1. `builder_tool_contract(tool_name="app_views_apply")`
|
|
8
|
-
2. `
|
|
9
|
-
3. `
|
|
8
|
+
2. `app_get_fields`
|
|
9
|
+
3. `app_get_views`
|
|
10
10
|
4. `app_views_apply`
|
|
11
|
-
5. `
|
|
11
|
+
5. `app_get_views` again whenever apply returns `failed` or `partial_success`
|
|
12
12
|
|
|
13
13
|
If you are unsure about keys or view types, call `builder_tool_contract(tool_name="app_views_apply")` before guessing.
|
|
14
14
|
|
|
@@ -27,7 +27,7 @@ Canonical rules before any example:
|
|
|
27
27
|
- Treat `fields` only as a legacy alias the MCP may normalize, not as the preferred shape
|
|
28
28
|
- Use `filters` with canonical keys `field_name`, `operator`, `value`/`values`
|
|
29
29
|
- For gantt, use `start_field`, `end_field`, and optionally `title_field`
|
|
30
|
-
- If `
|
|
30
|
+
- If `app_get_views` shows duplicate view names, include `view_key` in `upsert_views[]` and update that exact target
|
|
31
31
|
|
|
32
32
|
Apply a default table view:
|
|
33
33
|
|
|
@@ -136,7 +136,7 @@ Do not repeat `app_views_apply` with guessed keys. First:
|
|
|
136
136
|
|
|
137
137
|
1. check `suggested_next_call`
|
|
138
138
|
2. reuse `canonical_arguments` if present
|
|
139
|
-
3. call `
|
|
139
|
+
3. call `app_get_views` to see whether any requested views landed anyway
|
|
140
140
|
4. if needed, call `builder_tool_contract`
|
|
141
141
|
5. retry only the minimal failed view patch
|
|
142
142
|
|
|
@@ -155,8 +155,8 @@ Do not tell the user the filter is active until the readback verification matche
|
|
|
155
155
|
|
|
156
156
|
- `fields` is accepted as an alias for `columns`, but skill examples should still use `columns`
|
|
157
157
|
- `column_names` should not appear in skill examples
|
|
158
|
-
- `
|
|
159
|
-
- If `app_views_apply` returns `AMBIGUOUS_VIEW`, stop and re-run `
|
|
158
|
+
- `app_get_views` should be treated as canonical readback and now returns `columns`
|
|
159
|
+
- If `app_views_apply` returns `AMBIGUOUS_VIEW`, stop and re-run `app_get_views`; then retry with the exact `view_key`
|
|
160
160
|
- `filters` are ANDed together as one flat condition group
|
|
161
161
|
- `app_views_apply` publishes by default
|
|
162
162
|
- For select-style filters, success means the backend preserved the option value in readback, not just that the view name now exists
|
|
@@ -187,7 +187,8 @@ class FlowConditionRulePatch(StrictModel):
|
|
|
187
187
|
return value
|
|
188
188
|
payload = dict(value)
|
|
189
189
|
if "value" in payload and "values" not in payload:
|
|
190
|
-
|
|
190
|
+
raw_value = payload.pop("value")
|
|
191
|
+
payload["values"] = list(raw_value) if isinstance(raw_value, list) else [raw_value]
|
|
191
192
|
raw_operator = payload.get("operator", payload.get("op"))
|
|
192
193
|
if isinstance(raw_operator, str):
|
|
193
194
|
normalized = raw_operator.strip().lower()
|
|
@@ -238,7 +239,8 @@ class ViewFilterRulePatch(StrictModel):
|
|
|
238
239
|
return value
|
|
239
240
|
payload = dict(value)
|
|
240
241
|
if "value" in payload and "values" not in payload:
|
|
241
|
-
|
|
242
|
+
raw_value = payload.pop("value")
|
|
243
|
+
payload["values"] = list(raw_value) if isinstance(raw_value, list) else [raw_value]
|
|
242
244
|
raw_operator = payload.get("operator", payload.get("op"))
|
|
243
245
|
if isinstance(raw_operator, str):
|
|
244
246
|
normalized = raw_operator.strip().lower()
|
|
@@ -1092,7 +1094,8 @@ class ChartFilterRulePatch(StrictModel):
|
|
|
1092
1094
|
return value
|
|
1093
1095
|
payload = dict(value)
|
|
1094
1096
|
if "value" in payload and "values" not in payload:
|
|
1095
|
-
|
|
1097
|
+
raw_value = payload.pop("value")
|
|
1098
|
+
payload["values"] = list(raw_value) if isinstance(raw_value, list) else [raw_value]
|
|
1096
1099
|
raw_operator = payload.get("operator", payload.get("op"))
|
|
1097
1100
|
if isinstance(raw_operator, str):
|
|
1098
1101
|
normalized = raw_operator.strip().lower()
|
|
@@ -1338,7 +1341,7 @@ class PortalApplyRequest(StrictModel):
|
|
|
1338
1341
|
FieldPatch.model_rebuild()
|
|
1339
1342
|
|
|
1340
1343
|
|
|
1341
|
-
class
|
|
1344
|
+
class AppGetResponse(StrictModel):
|
|
1342
1345
|
app_key: str
|
|
1343
1346
|
title: str | None = None
|
|
1344
1347
|
app_icon: str | None = None
|
|
@@ -1349,39 +1352,48 @@ class AppReadSummaryResponse(StrictModel):
|
|
|
1349
1352
|
view_count: int = 0
|
|
1350
1353
|
workflow_enabled: bool = False
|
|
1351
1354
|
verification_hints: list[str] = Field(default_factory=list)
|
|
1355
|
+
editability: dict[str, bool | None] = Field(default_factory=dict)
|
|
1352
1356
|
|
|
1353
1357
|
|
|
1354
|
-
class
|
|
1358
|
+
class AppGetFieldsResponse(StrictModel):
|
|
1355
1359
|
app_key: str
|
|
1356
1360
|
fields: list[dict[str, Any]] = Field(default_factory=list)
|
|
1357
1361
|
field_count: int = 0
|
|
1358
1362
|
|
|
1359
1363
|
|
|
1360
|
-
class
|
|
1364
|
+
class AppGetLayoutResponse(StrictModel):
|
|
1361
1365
|
app_key: str
|
|
1362
1366
|
sections: list[dict[str, Any]] = Field(default_factory=list)
|
|
1363
1367
|
unplaced_fields: list[str] = Field(default_factory=list)
|
|
1364
1368
|
layout_mode_detected: str = "empty"
|
|
1365
1369
|
|
|
1366
1370
|
|
|
1367
|
-
class
|
|
1371
|
+
class AppGetViewsResponse(StrictModel):
|
|
1368
1372
|
app_key: str
|
|
1369
1373
|
views: list[dict[str, Any]] = Field(default_factory=list)
|
|
1370
1374
|
|
|
1371
1375
|
|
|
1372
|
-
class
|
|
1376
|
+
class AppGetFlowResponse(StrictModel):
|
|
1373
1377
|
app_key: str
|
|
1374
1378
|
enabled: bool = False
|
|
1375
1379
|
nodes: list[dict[str, Any]] = Field(default_factory=list)
|
|
1376
1380
|
transitions: list[dict[str, Any]] = Field(default_factory=list)
|
|
1377
1381
|
|
|
1378
1382
|
|
|
1379
|
-
class
|
|
1383
|
+
class AppGetChartsResponse(StrictModel):
|
|
1380
1384
|
app_key: str
|
|
1381
1385
|
charts: list[dict[str, Any]] = Field(default_factory=list)
|
|
1382
1386
|
chart_count: int = 0
|
|
1383
1387
|
|
|
1384
1388
|
|
|
1389
|
+
AppReadSummaryResponse = AppGetResponse
|
|
1390
|
+
AppFieldsReadResponse = AppGetFieldsResponse
|
|
1391
|
+
AppLayoutReadResponse = AppGetLayoutResponse
|
|
1392
|
+
AppViewsReadResponse = AppGetViewsResponse
|
|
1393
|
+
AppFlowReadResponse = AppGetFlowResponse
|
|
1394
|
+
AppChartsReadResponse = AppGetChartsResponse
|
|
1395
|
+
|
|
1396
|
+
|
|
1385
1397
|
class PortalListResponse(StrictModel):
|
|
1386
1398
|
items: list[dict[str, Any]] = Field(default_factory=list)
|
|
1387
1399
|
total: int = 0
|
|
@@ -1415,7 +1427,7 @@ class PortalGetResponse(StrictModel):
|
|
|
1415
1427
|
|
|
1416
1428
|
|
|
1417
1429
|
class ViewGetResponse(StrictModel):
|
|
1418
|
-
|
|
1430
|
+
view_key: str
|
|
1419
1431
|
base_info: dict[str, Any] = Field(default_factory=dict)
|
|
1420
1432
|
config: dict[str, Any] = Field(default_factory=dict)
|
|
1421
1433
|
questions: list[dict[str, Any]] = Field(default_factory=list)
|
|
@@ -1426,7 +1438,6 @@ class ChartGetResponse(StrictModel):
|
|
|
1426
1438
|
chart_id: str
|
|
1427
1439
|
base: dict[str, Any] = Field(default_factory=dict)
|
|
1428
1440
|
config: dict[str, Any] = Field(default_factory=dict)
|
|
1429
|
-
data: dict[str, Any] = Field(default_factory=dict)
|
|
1430
1441
|
|
|
1431
1442
|
|
|
1432
1443
|
class SchemaPlanRequest(StrictModel):
|