@josephyan/qingflow-app-user-mcp 0.2.0-beta.3 → 0.2.0-beta.31
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 +6 -3
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/skills/qingflow-app-user/SKILL.md +23 -137
- package/skills/qingflow-app-user/agents/openai.yaml +2 -2
- package/skills/qingflow-app-user/references/data-gotchas.md +22 -21
- package/skills/qingflow-app-user/references/environments.md +1 -1
- package/skills/qingflow-app-user/references/record-patterns.md +85 -46
- package/skills/qingflow-app-user/references/workflow-usage.md +10 -8
- package/skills/qingflow-record-analysis/SKILL.md +148 -0
- package/skills/qingflow-record-analysis/agents/openai.yaml +4 -0
- package/skills/qingflow-record-analysis/references/analysis-gotchas.md +145 -0
- package/skills/qingflow-record-analysis/references/analysis-patterns.md +125 -0
- package/skills/qingflow-record-analysis/references/confidence-reporting.md +92 -0
- package/skills/qingflow-record-analysis/references/dsl-templates.md +93 -0
- package/skills/qingflow-record-crud/SKILL.md +132 -0
- package/skills/qingflow-record-crud/agents/openai.yaml +5 -0
- package/skills/qingflow-record-crud/references/data-gotchas.md +44 -0
- package/skills/qingflow-record-crud/references/environments.md +58 -0
- package/skills/qingflow-record-crud/references/record-patterns.md +130 -0
- package/skills/qingflow-task-ops/SKILL.md +125 -0
- package/skills/qingflow-task-ops/agents/openai.yaml +4 -0
- package/skills/qingflow-task-ops/references/environments.md +44 -0
- package/skills/qingflow-task-ops/references/workflow-usage.md +27 -0
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/builder_facade/models.py +294 -1
- package/src/qingflow_mcp/builder_facade/service.py +2597 -198
- package/src/qingflow_mcp/server.py +85 -16
- package/src/qingflow_mcp/server_app_builder.py +70 -1
- package/src/qingflow_mcp/server_app_user.py +91 -188
- package/src/qingflow_mcp/solution/compiler/form_compiler.py +1 -1
- package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +21 -2
- package/src/qingflow_mcp/solution/executor.py +34 -7
- package/src/qingflow_mcp/tools/ai_builder_tools.py +1025 -29
- package/src/qingflow_mcp/tools/app_tools.py +110 -13
- package/src/qingflow_mcp/tools/approval_tools.py +357 -75
- package/src/qingflow_mcp/tools/directory_tools.py +203 -31
- package/src/qingflow_mcp/tools/file_tools.py +1 -0
- package/src/qingflow_mcp/tools/record_tools.py +3388 -975
- package/src/qingflow_mcp/tools/task_tools.py +376 -225
- package/src/qingflow_mcp/tools/workflow_tools.py +78 -4
package/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Install:
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npm install @josephyan/qingflow-app-user-mcp@0.2.0-beta.
|
|
6
|
+
npm install @josephyan/qingflow-app-user-mcp@0.2.0-beta.31
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Run:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx -y -p @josephyan/qingflow-app-user-mcp@0.2.0-beta.
|
|
12
|
+
npx -y -p @josephyan/qingflow-app-user-mcp@0.2.0-beta.31 qingflow-app-user-mcp
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Environment:
|
|
@@ -20,9 +20,12 @@ Environment:
|
|
|
20
20
|
|
|
21
21
|
This package bootstraps a local Python runtime on first install and then starts the `qingflow-app-user-mcp` stdio MCP server.
|
|
22
22
|
|
|
23
|
-
Bundled
|
|
23
|
+
Bundled skills:
|
|
24
24
|
|
|
25
25
|
- `skills/qingflow-app-user`
|
|
26
|
+
- `skills/qingflow-record-crud`
|
|
27
|
+
- `skills/qingflow-task-ops`
|
|
28
|
+
- `skills/qingflow-record-analysis`
|
|
26
29
|
|
|
27
30
|
Note:
|
|
28
31
|
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -1,158 +1,44 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: qingflow-app-user
|
|
3
|
-
description:
|
|
3
|
+
description: Route Qingflow end-user requests to the right specialized operational skill after the MCP is already connected and authenticated. Use when the task is operational but it is not yet clear whether it is record CRUD or final analysis.
|
|
4
4
|
metadata:
|
|
5
|
-
short-description:
|
|
5
|
+
short-description: Router for Qingflow operational skills
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Qingflow App User
|
|
9
9
|
|
|
10
10
|
## Overview
|
|
11
11
|
|
|
12
|
-
This skill is
|
|
12
|
+
This skill is a lightweight router for operational Qingflow work.
|
|
13
|
+
Assumes MCP is connected, authenticated, and on the correct workspace.
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
When the task is in `prod`, browser parity matters, or the user says "the page has data but MCP does not", restate the expected `base_url` and `qf_version`, then prefer tools that expose `request_route` so you can confirm the live route before concluding.
|
|
15
|
+
## Default Paths
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Route to exactly one of these specialized paths:
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
1. Record CRUD
|
|
20
|
+
Switch to [$qingflow-record-crud](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-crud/SKILL.md)
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
- `record_write_plan`
|
|
24
|
-
- `record_field_resolve`
|
|
25
|
-
- `record_aggregate`
|
|
26
|
-
- `record_create`
|
|
27
|
-
- `record_get`
|
|
28
|
-
- `record_update`
|
|
29
|
-
- `record_delete`
|
|
22
|
+
2. Analysis
|
|
23
|
+
Switch to [$qingflow-record-analysis](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-analysis/SKILL.md)
|
|
30
24
|
|
|
31
|
-
|
|
25
|
+
3. MCP connection / auth / workspace selection
|
|
26
|
+
Switch to [$qingflow-mcp-setup](/Users/yanqidong/.codex/skills/qingflow-mcp-setup/SKILL.md)
|
|
32
27
|
|
|
33
|
-
|
|
34
|
-
- `directory_list_internal_users`
|
|
35
|
-
- `directory_list_all_internal_users`
|
|
36
|
-
- `directory_list_internal_departments`
|
|
37
|
-
- `directory_list_all_departments`
|
|
38
|
-
- `directory_list_sub_departments`
|
|
39
|
-
- `directory_list_external_members`
|
|
28
|
+
## Routing Rules
|
|
40
29
|
|
|
41
|
-
|
|
30
|
+
- If the user does not know the target `app_key`, discover apps first with `app_list` or `app_search`, then route to the specialized skill
|
|
31
|
+
- If the task is about browsing, reading, creating, updating, deleting, attachments, relations, subtable writes, or member/department-field candidate lookup, switch to `$qingflow-record-crud`
|
|
32
|
+
- If the task is about grouped distributions, ratios, rankings, trends, insights, or any final statistical conclusion, switch to `$qingflow-record-analysis`
|
|
33
|
+
- If the MCP is not connected, authenticated, or bound to the right workspace, switch to `$qingflow-mcp-setup`
|
|
42
34
|
|
|
43
|
-
|
|
44
|
-
- `task_approve`
|
|
45
|
-
- `task_reject`
|
|
46
|
-
- `task_rollback*`
|
|
47
|
-
- `task_transfer*`
|
|
35
|
+
## Shared Preconditions
|
|
48
36
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
-
|
|
52
|
-
- `task_list_grouped`
|
|
53
|
-
- `task_statistics`
|
|
54
|
-
- `task_urge`
|
|
55
|
-
|
|
56
|
-
Do not use builder-side tools here:
|
|
57
|
-
|
|
58
|
-
- `app_*`
|
|
59
|
-
- `view_*`
|
|
60
|
-
- `workflow_*`
|
|
61
|
-
- `portal_*`
|
|
62
|
-
- `navigation_*`
|
|
63
|
-
- `package_*`
|
|
64
|
-
- `solution_*`
|
|
65
|
-
|
|
66
|
-
## Standard Operating Order
|
|
67
|
-
|
|
68
|
-
1. Ensure auth exists
|
|
69
|
-
2. Ensure workspace is selected
|
|
70
|
-
3. Confirm target app, task scope, and operation type
|
|
71
|
-
4. For org, member, department, approver, or ownership questions, start with `directory_*`
|
|
72
|
-
5. For inbox, pending, processed, cc, or workload questions, start with `task_statistics`, `task_list`, or `task_list_grouped`
|
|
73
|
-
6. When a task query identifies the target record, switch to `record_get` or `record_query` for business data details
|
|
74
|
-
7. For non-trivial record reads, start with `record_query` and use `record_query_plan` first when field ids, filters, or scan scope are uncertain
|
|
75
|
-
8. For non-trivial writes, start with `record_write_plan`, especially when using `fields`
|
|
76
|
-
9. Prefer read-first when changing existing records
|
|
77
|
-
10. Report the affected task ids, record ids, member ids, department ids, or counts after actions
|
|
78
|
-
11. For `prod`, complex forms, attachments, or any unfamiliar schema, prefer `record_create(..., verify_write=true)` or read back immediately after create/update
|
|
79
|
-
|
|
80
|
-
## Data Rules
|
|
81
|
-
|
|
82
|
-
- Prefer `record_query` as the default read entry
|
|
83
|
-
- Treat `record_query(list)` as the default wide-table browse and export endpoint; pass explicit `select_columns`, do not expect raw answer arrays there, and let the tool auto-batch columns when the backend per-request field cap is hit
|
|
84
|
-
- Use `request_route` from tool responses to verify the active `base_url` and `qf_version` whenever route mismatches are plausible
|
|
85
|
-
- Use `directory_search` for fuzzy internal lookup across both members and departments
|
|
86
|
-
- Use `directory_list_all_internal_users` when the user explicitly wants a complete internal member list within the current workspace or within a specific department or role
|
|
87
|
-
- Use `directory_list_all_departments` when the user explicitly wants the full department tree or all departments under a root
|
|
88
|
-
- Use `directory_list_internal_departments` for keyword-based department search, not full exports
|
|
89
|
-
- Use `task_statistics` before `task_list` when the user only needs counts
|
|
90
|
-
- Use `task_list_grouped` when worksheet or group buckets matter
|
|
91
|
-
- Use `task_urge` only when the user clearly wants a reminder sent for a pending task
|
|
92
|
-
- Use `record_query_plan` before final statistics or when field selectors are ambiguous
|
|
93
|
-
- For precise record lookup, use `record_get` when `apply_id` is known
|
|
94
|
-
- Use `record_field_resolve` when the user gives field titles and you are not fully sure about the exact schema; do not guess ambiguous fields silently
|
|
95
|
-
- Treat field selectors as schema-first and platform-generic. Prefer exact field titles, then neutral aliases such as `创建时间`, `新增时间`, `负责人`, `部门`, `时间`, or `阶段` only when the tool resolves them clearly. Do not assume CRM shorthand like `销售`, `商机阶段`, `客户全称`, or similar domain shortcuts apply across arbitrary Qingflow apps
|
|
96
|
-
- For updates, inspect current data first unless the user already provided the exact target and patch
|
|
97
|
-
- For deletes, confirm the exact record scope and report the deleted ids
|
|
98
|
-
- When validating business data volume, use `effective_count` over raw backend totals
|
|
99
|
-
- For summary or aggregate conclusions, prefer `strict_full=true`
|
|
100
|
-
- In `prod`, prefer read-first even more strictly and avoid deletes unless the record scope is explicit in the conversation
|
|
101
|
-
- For attachments, first run `file_upload_local`, then pass the returned `attachment_value` into `record_create` or `record_update`; do not try to write local file paths directly into attachment fields
|
|
102
|
-
- For relation fields, first query the target app and resolve the referenced record `apply_id`; do not assume titles, numbers, or business keys can be written directly into a relation field
|
|
103
|
-
- For subtable fields, write a list of row objects keyed by the subfield titles. When updating existing rows, include `rowId` / `row_id` / `__row_id__` only if the source record already exposes it
|
|
104
|
-
- Treat `14/34/35/36` as unsupported direct-write field types in app-user flows:
|
|
105
|
-
- `14`: time range
|
|
106
|
-
- `34`: image recognition
|
|
107
|
-
- `35`: image generation
|
|
108
|
-
- `36`: document parsing
|
|
109
|
-
- For those unsupported types, stop and explain the limitation instead of inventing payloads
|
|
110
|
-
- Use `record_write_plan` to inspect `write_format.support_level` before non-trivial writes:
|
|
111
|
-
- `full`: generic scalar/select/date writes are directly supported
|
|
112
|
-
- `restricted`: member/department/attachment/relation/subtable writes need the documented presteps
|
|
113
|
-
- `unsupported`: stop and explain the limitation
|
|
114
|
-
- For relation-heavy, attachment, subtable, or production writes, default to `verify_write=true` so field drops are surfaced immediately instead of being reported as success
|
|
115
|
-
|
|
116
|
-
## Mock and Demo Data
|
|
117
|
-
|
|
118
|
-
When the user asks for demo data, seed, smoke data, or mock data:
|
|
119
|
-
|
|
120
|
-
- default to at least `5` records for the relevant entity unless the user asks for fewer
|
|
121
|
-
- keep titles realistic and business-like
|
|
122
|
-
- vary statuses, dates, and categories enough to make views and charts useful
|
|
123
|
-
- if the task is `prod`, do not create mock or smoke data unless the user explicitly asks for it
|
|
124
|
-
|
|
125
|
-
## Response Interpretation
|
|
126
|
-
|
|
127
|
-
- low-level list totals from the backend may report `0` while rows are present; prefer `record_query(summary)` or `record_aggregate` for final conclusions
|
|
128
|
-
- `record_query(summary)` and `record_aggregate` expose `completeness`; do not treat partial scans as final conclusions
|
|
129
|
-
- `record_write_plan` is static preflight, not a guarantee that submit will pass runtime linkage or visibility checks
|
|
130
|
-
- `record_create` now returns integer `apply_id`; you can pass that id directly into `record_get`, `record_update`, or `record_delete`
|
|
131
|
-
- `verify_write=true` means the tool read the record back and compared the written fields; if it returns `status=verification_failed` or `ok=false`, do not report the create or update as successful
|
|
132
|
-
- Relation writes are `apply_id`-based; if the user only gives a title, number, or business key, query the target app first and resolve the real record id before writing
|
|
133
|
-
- Task counts and record counts are not interchangeable; a task query reflects task-center workload, not the underlying record total
|
|
134
|
-
- When reporting task results, include the task dimension that was used, such as pending, processed, cc, node, or worksheet
|
|
135
|
-
- Prefer summarizing titles and counts instead of dumping raw answer arrays
|
|
136
|
-
- When records reference other entities, verify references are coherent before reporting success
|
|
137
|
-
- `file_upload_local` may transparently change `effective_upload_kind` and `upload_protocol`; surface those fields when debugging production upload behavior instead of assuming all uploads are direct `PUT`
|
|
138
|
-
|
|
139
|
-
## Practical Patterns
|
|
140
|
-
|
|
141
|
-
- Bulk mock data creation: query current data first, run `record_write_plan`, then create missing records
|
|
142
|
-
- Data correction: query, inspect, preflight, update, and re-read
|
|
143
|
-
- Inbox triage: use `task_statistics` first, then `task_list` or `task_list_grouped`, then switch to `record_*` for the underlying record when needed
|
|
144
|
-
- Bottleneck analysis: start with `task_statistics` and `task_list_grouped` before drilling into specific records
|
|
145
|
-
- Workflow collaboration: comment, transfer, or reassign only after identifying the exact record
|
|
146
|
-
- Approval actions: identify the exact record and current node first, then use `task_approve` or `task_reject`; do not guess `nodeId`
|
|
147
|
-
- Demo validation: create at least `5` rows and confirm they are queryable
|
|
148
|
-
- Org export: use `directory_list_all_internal_users` for full member exports and `directory_list_all_departments` for full org-tree exports before mapping owners or departments into record operations
|
|
149
|
-
- Attachment write: upload first, write the returned URL object second, and prefer `verify_write=true`
|
|
150
|
-
- Relation write: query the target app first, capture the referenced record `apply_id`, then write the relation field and verify the readback
|
|
151
|
-
- Production discrepancy triage: compare the response `request_route` with the browser environment before assuming the data query is wrong
|
|
37
|
+
- prefer canonical app ids, record ids, task ids, and workflow node ids over guessed names
|
|
38
|
+
- if a field or target is still ambiguous after schema/task lookup, ask the user to confirm from a short candidate list instead of guessing
|
|
39
|
+
- if the task can stay read-only, do not write or act
|
|
152
40
|
|
|
153
41
|
## Resources
|
|
154
42
|
|
|
155
|
-
-
|
|
156
|
-
-
|
|
157
|
-
- Workflow usage actions: [references/workflow-usage.md](references/workflow-usage.md)
|
|
158
|
-
- Data gotchas: [references/data-gotchas.md](references/data-gotchas.md)
|
|
43
|
+
- Record CRUD: [$qingflow-record-crud](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-crud/SKILL.md)
|
|
44
|
+
- Dedicated analysis workflow: [$qingflow-record-analysis](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-analysis/SKILL.md)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "Qingflow App User"
|
|
3
|
-
short_description: "
|
|
4
|
-
default_prompt: "Use $qingflow-app-user
|
|
3
|
+
short_description: "Route Qingflow operational tasks to CRUD, task ops, or analysis"
|
|
4
|
+
default_prompt: "Use $qingflow-app-user as a router: switch to $qingflow-record-crud for record browse/read/write, switch to $qingflow-task-ops for task-center, comments, directory, and workflow usage actions, and switch to $qingflow-record-analysis for grouped analysis or final statistical conclusions."
|
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
# Data Gotchas
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
For final statistics, grouped distributions, rankings, trends, or insight-style conclusions, use [$qingflow-record-analysis](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-analysis/SKILL.md) instead of keeping that reasoning inside `$qingflow-app-user`.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- For `record_query(summary)` and `record_aggregate`, inspect `completeness` before concluding
|
|
7
|
-
- If the browser and MCP disagree, compare `request_route.base_url` and `request_route.qf_version` first
|
|
8
|
-
|
|
9
|
-
## Record titles
|
|
5
|
+
## Record Reads
|
|
10
6
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
7
|
+
- `record_list` is for browsing, export, and sample inspection only
|
|
8
|
+
- `record_get` is for one exact record
|
|
9
|
+
- Do not present paged browse output as if it were a grouped or full-population conclusion
|
|
10
|
+
- If the browser and MCP disagree, compare `request_route.base_url` and `request_route.qf_version` first
|
|
13
11
|
|
|
14
|
-
## Preflight
|
|
12
|
+
## Write Preflight
|
|
15
13
|
|
|
16
|
-
- `
|
|
17
|
-
- `
|
|
18
|
-
- Use `
|
|
19
|
-
- Prefer `
|
|
20
|
-
- `
|
|
21
|
-
- `apply_id` is normalized to an integer; pass it directly into later record tools
|
|
14
|
+
- `record_write` always performs internal static preflight before any apply
|
|
15
|
+
- If `record_write` returns `ok=false`, the write was blocked and not executed
|
|
16
|
+
- Use `record_schema_get` when field titles are uncertain instead of guessing ids
|
|
17
|
+
- Prefer `verify_write=true` for complex, relation-heavy, subtable, or production writes
|
|
18
|
+
- Even when `record_write` returns `ok=true`, it may still surface verification failures; do not report success before checking them
|
|
22
19
|
|
|
23
|
-
##
|
|
20
|
+
## Write Semantics
|
|
24
21
|
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
22
|
+
- `insert` uses `values`
|
|
23
|
+
- `update` uses `set`
|
|
24
|
+
- `delete` uses `record_id` or `record_ids`
|
|
25
|
+
- Do not send raw SQL strings
|
|
26
|
+
- Do not fake formula or expression fields
|
|
27
|
+
- Do not perform free-form bulk updates or deletes
|
|
28
|
+
- Do not guess relation targets from display text; resolve the real `record_id` first
|
|
28
29
|
|
|
29
30
|
## Attachments
|
|
30
31
|
|
|
@@ -36,10 +37,10 @@
|
|
|
36
37
|
|
|
37
38
|
- Subtable fields accept row objects keyed by subfield title, or native `tableValues`
|
|
38
39
|
- Use the current form schema's subfield titles; do not guess nested ids
|
|
39
|
-
- When updating existing subtable rows, preserve
|
|
40
|
+
- When updating existing subtable rows, preserve row ids if the source record returns them
|
|
40
41
|
- Nested subtable writes are still unsupported
|
|
41
42
|
|
|
42
|
-
## Unsupported
|
|
43
|
+
## Unsupported Direct-Write Fields
|
|
43
44
|
|
|
44
45
|
- `14` time range
|
|
45
46
|
- `34` image recognition
|
|
@@ -50,7 +50,7 @@ Production behavior:
|
|
|
50
50
|
Production guardrails:
|
|
51
51
|
|
|
52
52
|
- never assume a record id, app id, or workspace id
|
|
53
|
-
- treat `
|
|
53
|
+
- treat `record_write(operation="delete")` as high risk
|
|
54
54
|
- if the task can be answered read-only, do not write
|
|
55
55
|
|
|
56
56
|
## Reporting Rule
|
|
@@ -1,54 +1,96 @@
|
|
|
1
1
|
# Record Patterns
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
If the task shifts into grouped analysis, ratio, ranking, trend, or any final statistical conclusion, switch to [$qingflow-record-analysis](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-analysis/SKILL.md).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Browse Pattern
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- the target record id is unknown
|
|
9
|
-
- updates or deletes need confirmation
|
|
10
|
-
- summary analysis or final counts are needed
|
|
7
|
+
Use `record_schema_get -> record_list` when:
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
- the user wants to browse records
|
|
10
|
+
- the target `record_id` is unknown
|
|
11
|
+
- a delete or update target still needs confirmation
|
|
12
|
+
- the user needs sample rows or a small export
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
- filters are still in natural-language shape
|
|
16
|
-
- the result may be used as a final conclusion
|
|
17
|
-
- scan scope or completeness is unclear
|
|
14
|
+
Keep the browse DSL simple:
|
|
18
15
|
|
|
19
|
-
|
|
16
|
+
- `columns`: field ids only
|
|
17
|
+
- `where`: flat AND filters only
|
|
18
|
+
- `order_by`: field sorting only
|
|
19
|
+
- `limit` and `page`: browsing intent only
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
2. Resolve fields with `record_field_resolve` if needed. Prefer exact schema titles first; only rely on platform-neutral aliases such as `创建时间`, `负责人`, or `部门` when they resolve cleanly, and do not assume business-domain shorthand like `销售` is portable across apps
|
|
23
|
-
3. Run `record_write_plan` for non-trivial payloads or any `fields`-based write
|
|
24
|
-
4. For relation fields, query the target app first and resolve the referenced record `apply_id`
|
|
25
|
-
5. For attachments, call `file_upload_local` first and reuse the returned `attachment_value`
|
|
26
|
-
6. For subtable fields, pass a list of row objects keyed by subfield title. When updating existing rows, include `rowId` / `row_id` / `__row_id__` only if the current record already exposes it
|
|
27
|
-
7. Inspect `record_write_plan.data.support_matrix` or each field's `write_format.support_level` before submit:
|
|
28
|
-
- `full`: direct write is supported
|
|
29
|
-
- `restricted`: follow the documented presteps first
|
|
30
|
-
- `unsupported`: stop and explain the limitation
|
|
31
|
-
8. For complex forms, production writes, attachments, relation-heavy payloads, or subtables, create with `verify_write=true`
|
|
32
|
-
9. If verification fails, treat the write as not yet successful and inspect the missing or empty fields before reporting back
|
|
33
|
-
10. Re-query or fetch the record when validation matters
|
|
21
|
+
Do not use `record_list` for grouped conclusions, ratios, rankings, trends, or any final statistical claim.
|
|
34
22
|
|
|
35
|
-
##
|
|
23
|
+
## Detail Pattern
|
|
36
24
|
|
|
37
|
-
|
|
38
|
-
2. Resolve exact `apply_id`
|
|
39
|
-
3. Run `record_write_plan`
|
|
40
|
-
4. Update only the intended fields
|
|
41
|
-
5. Prefer `verify_write=true` for attachment, relation, subtable, or production updates
|
|
42
|
-
6. Re-read the record if the change is important, attachment-related, subtable-related, or the form has linkage
|
|
25
|
+
Use `record_schema_get -> record_get` when:
|
|
43
26
|
|
|
44
|
-
|
|
27
|
+
- the exact `record_id` is known
|
|
28
|
+
- the user needs one record in detail
|
|
29
|
+
- a write target needs verification before action
|
|
45
30
|
|
|
46
|
-
|
|
47
|
-
2. Confirm the target ids
|
|
48
|
-
3. Delete
|
|
49
|
-
4. Report affected ids and remaining count when relevant
|
|
31
|
+
Prefer passing explicit `columns` when the user only needs a subset of fields.
|
|
50
32
|
|
|
51
|
-
##
|
|
33
|
+
## Write Pattern
|
|
34
|
+
|
|
35
|
+
Use `record_schema_get -> record_write`.
|
|
36
|
+
|
|
37
|
+
1. Confirm the target app
|
|
38
|
+
2. Resolve fields with `record_schema_get`
|
|
39
|
+
3. Decide whether the task is `insert`, `update`, or `delete`
|
|
40
|
+
4. Build SQL-like JSON clauses
|
|
41
|
+
5. Run `record_write`
|
|
42
|
+
6. If `ok=false`, explain `field_errors` first, then summarize blockers; stop because the write was not executed
|
|
43
|
+
7. If `ok=true`, report the affected resource and any verification outcome
|
|
44
|
+
8. For important writes, keep `verify_write=true`
|
|
45
|
+
|
|
46
|
+
### Insert
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"operation": "insert",
|
|
51
|
+
"values": [
|
|
52
|
+
{ "field_id": 12, "value": "测试客户" },
|
|
53
|
+
{ "field_id": 18, "value": 1000 }
|
|
54
|
+
],
|
|
55
|
+
"submit_type": "submit",
|
|
56
|
+
"verify_write": true
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Update
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"operation": "update",
|
|
65
|
+
"record_id": 123,
|
|
66
|
+
"set": [
|
|
67
|
+
{ "field_id": 18, "value": 2000 }
|
|
68
|
+
],
|
|
69
|
+
"verify_write": true
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Delete
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"operation": "delete",
|
|
78
|
+
"record_ids": [123, 124]
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Write Anti-Patterns
|
|
83
|
+
|
|
84
|
+
Do not do this:
|
|
85
|
+
|
|
86
|
+
- do not send raw SQL text
|
|
87
|
+
- do not build free-form `WHERE` updates or deletes
|
|
88
|
+
- do not invent formulas or expressions
|
|
89
|
+
- do not auto-fill missing required fields
|
|
90
|
+
- do not guess relation targets without first resolving them
|
|
91
|
+
- do not claim a blocked `record_write` was executed
|
|
92
|
+
|
|
93
|
+
## Unsupported Direct Writes
|
|
52
94
|
|
|
53
95
|
Do not attempt direct app-user writes for these field types:
|
|
54
96
|
|
|
@@ -57,13 +99,10 @@ Do not attempt direct app-user writes for these field types:
|
|
|
57
99
|
- `35` image generation
|
|
58
100
|
- `36` document parsing
|
|
59
101
|
|
|
60
|
-
If the payload includes them, stop
|
|
61
|
-
|
|
62
|
-
## Relation fields
|
|
102
|
+
If the payload includes them, stop after the blocked `record_write` response and explain that the tool does not support a reliable direct write for those fields yet.
|
|
63
103
|
|
|
64
|
-
Relation
|
|
104
|
+
## Relation, Attachment, and Subtable Rules
|
|
65
105
|
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
- Do not write relation fields with display titles, business keys, or guessed identifiers unless they have already been resolved to the real record id
|
|
106
|
+
- Relation fields are record-id based. Resolve the referenced target first, then write the relation field with the real `record_id`.
|
|
107
|
+
- Attachment fields are two-step: upload first with `file_upload_local`, then reuse the returned attachment payload in `record_write`.
|
|
108
|
+
- Subtable writes require the current schema shape; when updating existing subtable rows, preserve row ids if the current record exposes them.
|
|
@@ -7,18 +7,20 @@ Examples:
|
|
|
7
7
|
- add a comment to a record
|
|
8
8
|
- approve or reject a workflow task
|
|
9
9
|
- transfer a task
|
|
10
|
-
- roll back a
|
|
11
|
-
- list
|
|
10
|
+
- roll back a task
|
|
11
|
+
- list todo, initiated, done, or cc tasks
|
|
12
|
+
- inspect workload by worksheet or workflow node
|
|
12
13
|
- urge a pending task
|
|
13
14
|
|
|
14
15
|
Rules:
|
|
15
16
|
|
|
16
17
|
- if the user starts from inbox, todo, workload, cc, or bottleneck language, use `task_*` first
|
|
17
|
-
- use `
|
|
18
|
-
- use `
|
|
18
|
+
- use `task_summary` for headline counts
|
|
19
|
+
- use `task_list` for flat browsing
|
|
20
|
+
- use `task_facets` when worksheet or workflow-node buckets matter
|
|
19
21
|
- treat task counts as task-center counts, not record counts
|
|
20
|
-
- switch to `record_*` after locating the exact business record behind a task
|
|
21
|
-
- identify the exact
|
|
22
|
-
- for approve or reject, identify the exact `
|
|
23
|
-
- avoid usage-side
|
|
22
|
+
- switch to `record_*` only after locating the exact business record behind a task
|
|
23
|
+
- identify the exact target first
|
|
24
|
+
- for approve or reject, identify the exact `workflow_node_id` first; prefer task-center results or current audit info, then use `task_approve` or `task_reject`
|
|
25
|
+
- avoid usage-side workflow actions on ambiguous records
|
|
24
26
|
- summarize the final action and target task ids or record ids
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qingflow-record-analysis
|
|
3
|
+
description: Analyze Qingflow record data safely after the MCP is already connected and authenticated. Use when the user wants grouped distributions, ratios, averages, rankings, trends, insights, or any final statistical conclusion across an existing app's data. Do not use this skill for schema changes, app design, or ordinary record CRUD unless they are strictly supporting an analysis flow.
|
|
4
|
+
metadata:
|
|
5
|
+
short-description: Analyze Qingflow record data with schema-first DSL execution
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Qingflow Record Analysis
|
|
9
|
+
|
|
10
|
+
This skill is for final statistical conclusions only.
|
|
11
|
+
Assumes MCP is connected, authenticated, and on the correct workspace.
|
|
12
|
+
Analysis tasks must start with `record_schema_get`. Read top-level `fields` and `suggested_*`, then build field_id-based DSLs only.
|
|
13
|
+
|
|
14
|
+
## Step 1: `record_schema_get` → Step 2: build DSL → Step 3: `record_analyze`
|
|
15
|
+
|
|
16
|
+
This is the ONLY execution order. Never skip step 1. Never call `record_analyze` without a schema.
|
|
17
|
+
|
|
18
|
+
Core tools: `record_schema_get`, `record_analyze`. Use `record_list`/`record_get` only for post-analysis samples; task/comment work stays in [$qingflow-task-ops](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-task-ops/SKILL.md).
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## DSL Contract
|
|
23
|
+
|
|
24
|
+
### DSL FORMAT (CRITICAL — read this FIRST)
|
|
25
|
+
|
|
26
|
+
### ✅ Correct vs ❌ Wrong — learn from these before building ANY DSL
|
|
27
|
+
|
|
28
|
+
**dimension item:**
|
|
29
|
+
```
|
|
30
|
+
✅ CORRECT: { "field_id": 9500572, "alias": "报价类型" }
|
|
31
|
+
❌ WRONG: 9500572 ← bare integer, not a dict
|
|
32
|
+
❌ WRONG: "报价类型" ← string, not a dict
|
|
33
|
+
❌ WRONG: { "field_id": 9500572, "title": "报价类型" } ← "title" is forbidden
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**metric item — the key is `op`, NOT `type`/`agg`/`aggregation`:**
|
|
37
|
+
```
|
|
38
|
+
✅ CORRECT: { "op": "count", "alias": "记录数" }
|
|
39
|
+
✅ CORRECT: { "op": "sum", "field_id": 7, "alias": "总金额" }
|
|
40
|
+
❌ WRONG: { "type": "count" } ← "type" is NOT a valid key
|
|
41
|
+
❌ WRONG: { "agg": "count" } ← "agg" is NOT a valid key
|
|
42
|
+
❌ WRONG: { "aggregation": "count" } ← "aggregation" is NOT a valid key
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**filter item — the key is `op`, NOT `operator`:**
|
|
46
|
+
```
|
|
47
|
+
✅ CORRECT: { "field_id": 2, "op": "between", "value": ["2024-03-01", "2024-03-31"] }
|
|
48
|
+
✅ CORRECT: { "field_id": 5, "op": "eq", "value": "已完成" }
|
|
49
|
+
❌ WRONG: { "field_id": 2, "operator": "between", "value": [...] } ← "operator" is forbidden
|
|
50
|
+
❌ WRONG: { "field_id": 2, "op": ">=", "value": "2024-03-01" } ← ">=" is not valid, use "gte"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**sort item:**
|
|
54
|
+
```
|
|
55
|
+
✅ CORRECT: { "by": "记录数", "order": "desc" } ← "by" references an alias
|
|
56
|
+
❌ WRONG: { "by": 9500572, "order": "desc" } ← field_id not allowed in sort
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Allowed keys per item (ANY other key = error)
|
|
60
|
+
|
|
61
|
+
| Item | Allowed keys only |
|
|
62
|
+
|------|-------------------|
|
|
63
|
+
| dimension | `field_id`, `alias`, `bucket` |
|
|
64
|
+
| metric | `op`, `field_id`, `alias` |
|
|
65
|
+
| filter | `field_id`, `op`, `value` |
|
|
66
|
+
| sort | `by`, `order` |
|
|
67
|
+
|
|
68
|
+
### `op` values
|
|
69
|
+
|
|
70
|
+
- metrics: `count`, `sum`, `avg`, `min`, `max`, `distinct_count`
|
|
71
|
+
- filters: `eq`, `neq`, `in`, `not_in`, `gt`, `gte`, `lt`, `lte`, `between`, `contains`, `is_null`, `not_null`
|
|
72
|
+
- For `count` metric: do NOT pass `field_id`. For all others: `field_id` is required.
|
|
73
|
+
- If `metrics` is omitted or `[]`, defaults to `[{"op":"count","alias":"记录数"}]`.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
See [references/dsl-templates.md](references/dsl-templates.md) for complete copy-paste templates.
|
|
78
|
+
|
|
79
|
+
**Typical summary / distribution:**
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"dimensions": [{ "field_id": FIELD_ID_FROM_SCHEMA, "alias": "维度名" }],
|
|
83
|
+
"metrics": [{ "op": "count", "alias": "记录数" }],
|
|
84
|
+
"sort": [{ "by": "记录数", "order": "desc" }],
|
|
85
|
+
"limit": 50,
|
|
86
|
+
"strict_full": true
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Typical time-filter / trend:**
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"dimensions": [{ "field_id": TIME_FIELD_ID, "alias": "月份", "bucket": "month" }],
|
|
94
|
+
"metrics": [{ "op": "count", "alias": "记录数" }],
|
|
95
|
+
"filters": [{ "field_id": TIME_FIELD_ID, "op": "between", "value": ["2024-03-01", "2024-03-31"] }],
|
|
96
|
+
"sort": [{ "by": "月份", "order": "asc" }],
|
|
97
|
+
"limit": 24,
|
|
98
|
+
"strict_full": true
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Top-level arguments:
|
|
103
|
+
|
|
104
|
+
- `app_key`: required.
|
|
105
|
+
- `dimensions`: `[]` = whole-table summary; `[{...}]` = grouped.
|
|
106
|
+
- `strict_full`: `true` for final conclusions. `false` allows partial results.
|
|
107
|
+
- `limit`: limits returned rows only, not scan scope.
|
|
108
|
+
- `view_key`/`view_name`: optional scope narrowing.
|
|
109
|
+
- `bucket` in dimensions: only for `suggested_time_fields`. Values: `day`/`week`/`month`/`quarter`/`year`/`null`.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## RULES
|
|
114
|
+
|
|
115
|
+
- 渗透率 / 转化率 / 占比类结论必须先定义分子和分母。
|
|
116
|
+
- Do not claim a metric you did not query.
|
|
117
|
+
- Derived ratios must be computed outside the DSL.
|
|
118
|
+
- Before choosing a DSL shape, first decide whether the question needs `count`, `sum`, `avg`, `distinct_count`, `ratio`, or `ranking`.
|
|
119
|
+
- Rankings must come from structured sorted results.
|
|
120
|
+
- For partial answers, explicitly disclose which parts are complete and which parts remain unresolved.
|
|
121
|
+
- Complex answers should default to `先结构、后解读`.
|
|
122
|
+
- `between`: pass a two-item array.
|
|
123
|
+
- Sort entries must reference an alias already defined in `dimensions` or `metrics`.
|
|
124
|
+
- Final wording should stay as close as possible to schema titles.
|
|
125
|
+
- Do not pass field titles, aliases, or guessed ids.
|
|
126
|
+
- If `completeness.statement_scope=returned_groups_only` or `completeness.rows_truncated=true`, downgrade wording to returned groups only.
|
|
127
|
+
- One DSL per question. Multiple small DSLs > one overloaded request.
|
|
128
|
+
- `record_list` is NEVER the basis for final statistics.
|
|
129
|
+
- Set `alias` for any metric you will sort by, compare, or quote.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## OUTPUT
|
|
134
|
+
|
|
135
|
+
- Final answer must show concrete numbers.
|
|
136
|
+
- If `result.rows` exists, list each returned row; if there are more than 20 rows, show Top 20 and say so.
|
|
137
|
+
- 占比 = 行指标值 / `result.totals.metric_totals` 总值;如 `metric_totals` 缺失,用各行之和作分母。
|
|
138
|
+
- Prefer the structured `ranking` block when it exists.
|
|
139
|
+
- `safe_for_final_conclusion=true` → `全量可信结论`
|
|
140
|
+
- Otherwise → `初步观察`
|
|
141
|
+
- `rows_truncated=true` → 用 `前 N 个分组`, 不用 `全部`/`所有`
|
|
142
|
+
|
|
143
|
+
## Resources
|
|
144
|
+
|
|
145
|
+
- DSL templates: [references/dsl-templates.md](references/dsl-templates.md)
|
|
146
|
+
- Analysis patterns: [references/analysis-patterns.md](references/analysis-patterns.md)
|
|
147
|
+
- Confidence reporting: [references/confidence-reporting.md](references/confidence-reporting.md)
|
|
148
|
+
- Analysis gotchas: [references/analysis-gotchas.md](references/analysis-gotchas.md)
|