@adminforth/dashboard 1.4.2 → 1.5.0

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.
@@ -140,10 +140,6 @@ export const dashboardApi = {
140
140
  return callDashboardApi('/adminapi/v1/dashboard/get-config', { slug })
141
141
  },
142
142
 
143
- async setDashboardConfig(slug: string, config: unknown): Promise<DashboardResponse> {
144
- return callDashboardApi('/adminapi/v1/dashboard/set_dashboard_config', { slug, config })
145
- },
146
-
147
143
  async addDashboardGroup(slug: string): Promise<DashboardResponse> {
148
144
  return callDashboardApi('/adminapi/v1/dashboard/add_dashboard_group', { slug })
149
145
  },
@@ -5,232 +5,162 @@ description: Use when the user wants to view, create, update, move, remove, vali
5
5
 
6
6
  # AdminForth Dashboard Plugin
7
7
 
8
- This skill is action-oriented. When the user asks to create, add, edit, update, move, remove, or configure dashboard entities, complete the request by calling the dashboard tools. Do not satisfy dashboard mutation requests by only showing JSON, YAML, JavaScript, TypeScript, Zod schemas, or example config snippets.
8
+ Use this skill for dashboard group/widget mutations and dashboard data loading.
9
9
 
10
- ## Primary Rule
10
+ ## Core rule
11
11
 
12
- If callable dashboard tools are available, use them.
12
+ If dashboard tools are callable, use tools. Do not answer mutation requests by only printing config.
13
13
 
14
- A response that only shows a config object, schema, or code snippet is incomplete unless the user explicitly asked for a schema, code example, or explanation.
14
+ ## Entity boundaries
15
15
 
16
- For dashboard mutation requests, the expected flow is:
16
+ Dashboard root, groups, and widgets are different entities.
17
17
 
18
- 1. Load dashboard state when needed.
19
- 2. Choose or create the target group/widget.
20
- 3. Call the appropriate dashboard mutation tool. (WITHOUT USER CONFIRMATION)
21
- 4. Return a short result summary.
18
+ - Group tools use groupId and only change group config.
19
+ - Widget tools use widgetId and change target/query/card/chart/table/pivot.
20
+ - Never call dashboard_set_dashboard_group_config to configure a widget.
21
+ - Never call dashboard_add_dashboard_group to configure a widget.
22
+ - If widget target, label, query, chart, card, table, pivot, variables, formulas, filters, or display fields must change, use dashboard_set_widget_config.
22
23
 
23
- Do not print the widget config as the main answer instead of calling tools.
24
+ ## Tool routing
24
25
 
25
- ## User Intent Mapping
26
+ - Read dashboard: dashboard_get_config
27
+ - Add group: dashboard_add_dashboard_group
28
+ - Rename group: dashboard_set_dashboard_group_config
29
+ - Add widget slot: dashboard_add_dashboard_widget
30
+ - Configure widget: dashboard_set_widget_config
31
+ - Move/remove widget/group: matching move/remove tool
32
+ - Load widget data: dashboard_get_dashboard_widget_data
26
33
 
27
- Use dashboard tools for these intents:
34
+ If a known dashboard tool schema is missing, call fetch_tool_schema for that exact tool.
35
+ If fetch_tool_schema returns but the intended tool is still not callable, stop and report a tool-routing error. Do not substitute another mutation tool.
28
36
 
29
- - "add/create/write/make a widget" → create and configure a widget.
30
- - "change/update/edit this widget" → update widget config.
31
- - "move this widget/group" → call the move tool.
32
- - "remove/delete this widget/group" → call the remove tool.
33
- - "show/load dashboard" → call the dashboard config tool.
34
- - "load/check widget data" → call the widget data tool.
35
- - "validate this widget config" → call validation logic/tool if available.
37
+ ## Group creation guard
36
38
 
37
- If the user asks how the schema works, how to implement the API, or how to change backend code, then answer as a developer/code task instead of mutating the dashboard.
39
+ Before creating a group, call dashboard_get_config and check existing groups.
38
40
 
39
- ## Callable Dashboard Tools
41
+ - If a requested group label already exists, reuse that groupId.
42
+ - If no matching group exists, call dashboard_add_dashboard_group at most once for that requested group.
43
+ - After dashboard_add_dashboard_group succeeds, extract the new groupId from the returned dashboard response.
44
+ - If the group needs a label, call dashboard_set_dashboard_group_config once with that groupId.
45
+ - After that, the next mutation must be dashboard_add_dashboard_widget or dashboard_set_widget_config, not another dashboard_add_dashboard_group.
40
46
 
41
- Use these tools whenever available:
47
+ Never call dashboard_add_dashboard_group repeatedly for the same user request. If you are about to create a second group for the same label/section, stop and report:
42
48
 
43
- - `dashboard_get_config`
44
- - `dashboard_set_dashboard_config`
45
- - `dashboard_add_dashboard_group`
46
- - `dashboard_set_dashboard_group_config`
47
- - `dashboard_move_dashboard_group`
48
- - `dashboard_remove_dashboard_group`
49
- - `dashboard_add_dashboard_widget`
50
- - `dashboard_move_dashboard_widget`
51
- - `dashboard_remove_dashboard_widget`
52
- - `dashboard_set_widget_config`
53
- - `dashboard_get_dashboard_widget_data`
49
+ Repeated dashboard_add_dashboard_group; expected using the existing/new groupId.
54
50
 
55
- If a dashboard tool is known by name but its argument schema is not loaded, call `fetch_tool_schema` for that tool first. After the schema is loaded, call the dashboard tool. Do not guess arguments if `fetch_tool_schema` is available.
51
+ ## Create-and-configure workflow
56
52
 
57
- ## Tool Argument Rules
53
+ For any request to create KPI/chart/table/pivot/gauge widgets:
58
54
 
59
- Do not pass fields between dashboard tools by analogy. Use each tool's schema.
55
+ 1. dashboard_get_config
56
+ 2. select existing group by label, or create one group once
57
+ 3. if needed, rename group once
58
+ 4. for each widget:
59
+ - dashboard_add_dashboard_widget
60
+ - immediately dashboard_set_widget_config for the returned widgetId
61
+ - confirm target is not empty
62
+ 5. dashboard_get_config
63
+ 6. validate all requested widgets are configured
64
+ 7. return short summary
60
65
 
61
- - `dashboard_add_dashboard_group` creates a new group. It accepts the dashboard slug only. Never pass `groupId` to this tool.
62
- - `dashboard_set_dashboard_config` replaces the full dashboard config. Use it when the user explicitly asks to edit the whole dashboard config.
63
- - `dashboard_add_dashboard_widget` creates a widget inside an existing group. Use it when you already have a `groupId`.
64
- - `dashboard_set_dashboard_group_config`, `dashboard_move_dashboard_group`, and `dashboard_remove_dashboard_group` operate on an existing group and need `groupId`.
65
- - `dashboard_set_widget_config`, `dashboard_move_dashboard_widget`, `dashboard_remove_dashboard_widget`, and `dashboard_get_dashboard_widget_data` operate on an existing widget and need `widgetId`.
66
- - If a tool call fails with "input did not match expected schema", call `fetch_tool_schema` for that exact tool, remove unsupported arguments, and retry the correct tool.
66
+ Do not batch-create empty widgets and postpone configuration.
67
+ Do not build a full dashboard JSON object for this workflow.
67
68
 
68
- ## Widget Creation Workflow
69
+ ## Empty widget rule
69
70
 
70
- For requests like:
71
+ dashboard_add_dashboard_widget creates only:
71
72
 
72
- - "add a table widget"
73
- - "create a chart"
74
- - "write a widget showing top 5 orders"
75
- - "make a widget for revenue by product"
73
+ label: New widget
74
+ target: empty
76
75
 
77
- do this:
76
+ This is incomplete for KPI/chart/table/pivot/gauge/spend/revenue/usage widgets.
78
77
 
79
- 1. Call `dashboard_get_config` with the requested slug, or `default` if slug is not specified.
80
- 2. Select the requested group. If the group is not specified, use the first existing group.
81
- 3. If there are no groups, call `dashboard_add_dashboard_group`.
82
- 4. Call `dashboard_add_dashboard_widget` with the selected group id.
83
- 5. Call `dashboard_set_widget_config` with the returned widget id and schema-valid config.
84
- 6. Return a short summary with dashboard slug, group id, widget id, target, label, resource, selected fields, order, and limit.
78
+ ## No-op loop guard
85
79
 
86
- Do not stop after generating config text.
80
+ If the same mutation tool is about to be called with the same payload twice, stop and reassess.
81
+ If dashboard_add_dashboard_group repeats for the same requested group, stop and reuse the groupId from dashboard_get_config.
82
+ If dashboard_set_dashboard_group_config repeats while new widgets are target: empty, use dashboard_set_widget_config instead.
83
+ After 2 repeated no-op mutations, stop with an explicit error.
87
84
 
88
- ## Widget Update Workflow
85
+ ## State machine
89
86
 
90
- For requests like:
87
+ For create group + widgets tasks, follow this exact state order:
91
88
 
92
- - "change this widget"
93
- - "make the chart use another field"
94
- - "update the widget config"
95
- - "turn this widget into a table"
89
+ dashboard_get_config
90
+ -> maybe dashboard_add_dashboard_group
91
+ -> maybe dashboard_set_dashboard_group_config
92
+ -> dashboard_add_dashboard_widget
93
+ -> dashboard_set_widget_config
94
+ -> repeat only the two widget steps for more widgets
95
+ -> dashboard_get_config
96
96
 
97
- do this:
97
+ Allowed repeats:
98
+ - dashboard_add_dashboard_widget may repeat once per requested widget.
99
+ - dashboard_set_widget_config may repeat once per requested widget.
98
100
 
99
- 1. Call `dashboard_get_config`.
100
- 2. Find the widget by id, label, or clear context.
101
- 3. Build the new config while preserving server-owned fields handled by the API.
102
- 4. Call `dashboard_set_widget_config`.
103
- 5. Return a short summary of what changed.
101
+ Forbidden repeats:
102
+ - dashboard_add_dashboard_group for the same requested group.
103
+ - dashboard_set_dashboard_group_config with the same label/groupId.
104
104
 
105
- If the widget cannot be identified, ask only for the missing widget id or label.
105
+ Forbidden substitutions:
106
+ - dashboard_set_dashboard_group_config instead of set widget config.
107
+ - dashboard_add_dashboard_group instead of add widget.
106
108
 
107
- ## Group Workflow
109
+ ## Widget config keys
108
110
 
109
- For group requests:
111
+ Use current keys:
112
+ target, label, query, resource, group_by, order_by, page_size, variables.
113
+ Use card for kpi_card/gauge_card.
114
+ Use chart for chart.
115
+ Use table for table.
116
+ Use pivot for pivot_table.
110
117
 
111
- - Add group → `dashboard_add_dashboard_group`
112
- - Rename/change group config → `dashboard_set_dashboard_group_config`
113
- - Move group → `dashboard_move_dashboard_group`
114
- - Remove group → `dashboard_remove_dashboard_group`
118
+ Use target, not type.
119
+ Use query, not dataSource.
120
+ Use resource, not resourceId.
115
121
 
116
- If slug is missing, use `default`.
122
+ ## Query shape rules
117
123
 
118
- ## Dashboard Config Workflow
124
+ Use query.steps only for funnel charts. Do not use query.steps for kpi_card, gauge_card, table, pivot_table, or normal bar/line/stacked/pie charts.
119
125
 
120
- Use `dashboard_set_dashboard_config` only when the user explicitly asks to edit the whole dashboard root config.
126
+ For kpi_card and normal charts, use:
127
+ - query.resource
128
+ - query.select
129
+ - optional query.filters
130
+ - optional query.group_by
131
+ - optional query.period
132
+ - optional query.order_by
133
+ - optional query.calcs
121
134
 
122
- For requests like:
135
+ Calculations run after selected fields and aggregates are loaded into a row. Therefore:
136
+ - aggregate real resource fields first
137
+ - then calculate derived fields from those aggregate aliases
138
+ - do not aggregate a calc alias such as cost unless cost is an actual resource field
123
139
 
124
- - "update root dashboard config"
125
- - "replace the whole dashboard config"
140
+ For spend/cost widgets, prefer this pattern:
126
141
 
127
- do this:
142
+ select raw token totals:
143
+ - sum uncached_input_tokens as uncached_input_tokens
144
+ - sum cached_input_tokens as cached_input_tokens
145
+ - sum output_tokens as output_tokens
128
146
 
129
- 1. Call `dashboard_get_config`.
130
- 2. Modify the returned root config, preserving existing `version`, `groups`, and `widgets` unless the user asked to change them.
131
- 3. Call `dashboard_set_dashboard_config` with the full updated config.
132
- 4. Return a short summary of the root-level fields changed.
147
+ then query.calcs:
148
+ - calculate total_spend from those aliases and lookup variables
133
149
 
134
- Do not use `dashboard_set_dashboard_config` to store reusable widget variables.
150
+ For today vs yesterday KPI, use multiple aggregate select items with filters and distinct aliases, then calcs. Do not use query.steps.
135
151
 
136
- ## Widget Config Rules
152
+ ## Calc variables
137
153
 
138
- Use the current schema keys exactly:
154
+ Use variables for static maps/rates.
155
+ Use lookup($variables.some.map, row_field, default_number) in query.calcs.
139
156
 
140
- - Use `target`, not `type`.
141
- - Use `label`, not `title`.
142
- - Use `query`, not `dataSource`.
143
- - Use `resource`, not `resourceId`.
144
- - Use `group_by`, not `groupBy`.
145
- - Use `order_by`, not `orderBy`.
146
- - Use `page_size`, not `pageSize`.
147
- - For step-based chart queries, use `query.steps` as an ordered array of `{ name, resource, metric, filters }` steps and add `query.calcs` when derived fields are needed.
148
- - Use `card` for KPI and gauge widget view config.
149
- - Use `pivot` for pivot table view config.
150
- - Use `variables` for reusable static maps or constants at widget level.
151
- - In `query.calcs`, use `lookup($variables.some.map, row_field, default_number)` to read a numeric value from a variable map by the current row/group field.
157
+ Minimal example:
152
158
 
153
- ## Variables And Lookup Calcs
154
-
155
- Widget config can define variables:
156
-
157
- ```yaml
158
- variables:
159
- token_prices_per_1m:
160
- input:
161
- gpt-4.1: 2.00
162
- gpt-4.1-mini: 0.40
163
- gpt-4o-mini: 0.15
164
- output:
165
- gpt-4.1: 8.00
166
- gpt-4.1-mini: 1.60
167
- gpt-4o-mini: 0.60
168
- cached:
169
- gpt-4.1: 0.50
170
- gpt-4.1-mini: 0.10
171
- gpt-4o-mini: 0.075
172
- ```
173
-
174
- Use variables when a calculation needs a static rate table, threshold table, coefficient map, or other reusable constants. In calcs, `lookup($variables.path.to.map, field_name, 0)` returns the value from the map using `field_name` from the current row/group. The third argument is the numeric fallback when the key is missing.
175
-
176
- Example widget:
177
-
178
- ```yaml
179
- target: chart
180
- label: Model costs
181
- size: large
182
159
  variables:
183
- token_prices_per_1m:
184
- input:
185
- gpt-4.1: 2.00
186
- gpt-4.1-mini: 0.40
187
- gpt-4o-mini: 0.15
188
- output:
189
- gpt-4.1: 8.00
190
- gpt-4.1-mini: 1.60
191
- gpt-4o-mini: 0.60
192
- cached:
193
- gpt-4.1: 0.50
194
- gpt-4.1-mini: 0.10
195
- gpt-4o-mini: 0.075
196
-
197
- chart:
198
- type: stacked_bar
199
- title: LLM costs by model
200
- x:
201
- field: model
202
- label: Model
203
- y:
204
- - field: input_cost
205
- label: Input
206
- format: currency
207
- - field: output_cost
208
- label: Output
209
- format: currency
210
- - field: cached_cost
211
- label: Cached
212
- format: currency
160
+ prices:
161
+ gpt-5.4: 2.5
213
162
 
214
163
  query:
215
- resource: model_usage
216
- select:
217
- - field: model
218
- - agg: sum
219
- field: input_tokens
220
- as: input_tokens
221
- - agg: sum
222
- field: output_tokens
223
- as: output_tokens
224
- - agg: sum
225
- field: cached_tokens
226
- as: cached_tokens
227
- group_by:
228
- - model
229
164
  calcs:
230
- - calc: input_tokens / 1000000 * lookup($variables.token_prices_per_1m.input, model, 0)
231
- as: input_cost
232
- - calc: output_tokens / 1000000 * lookup($variables.token_prices_per_1m.output, model, 0)
233
- as: output_cost
234
- - calc: cached_tokens / 1000000 * lookup($variables.token_prices_per_1m.cached, model, 0)
235
- as: cached_cost
236
- ```
165
+ - calc: tokens / 1000000 * lookup($variables.prices, model, 0)
166
+ as: cost
@@ -22,7 +22,6 @@ export declare class DashboardApiError extends Error {
22
22
  }
23
23
  export declare const dashboardApi: {
24
24
  getDashboardConfig(slug: string): Promise<DashboardResponse>;
25
- setDashboardConfig(slug: string, config: unknown): Promise<DashboardResponse>;
26
25
  addDashboardGroup(slug: string): Promise<DashboardResponse>;
27
26
  moveDashboardGroup(slug: string, groupId: string, direction: DashboardGroupMoveDirection): Promise<DashboardResponse>;
28
27
  removeDashboardGroup(slug: string, groupId: string): Promise<DashboardResponse>;
@@ -99,11 +99,6 @@ export const dashboardApi = {
99
99
  return callDashboardApi('/adminapi/v1/dashboard/get-config', { slug });
100
100
  });
101
101
  },
102
- setDashboardConfig(slug, config) {
103
- return __awaiter(this, void 0, void 0, function* () {
104
- return callDashboardApi('/adminapi/v1/dashboard/set_dashboard_config', { slug, config });
105
- });
106
- },
107
102
  addDashboardGroup(slug) {
108
103
  return __awaiter(this, void 0, void 0, function* () {
109
104
  return callDashboardApi('/adminapi/v1/dashboard/add_dashboard_group', { slug });
@@ -140,10 +140,6 @@ export const dashboardApi = {
140
140
  return callDashboardApi('/adminapi/v1/dashboard/get-config', { slug })
141
141
  },
142
142
 
143
- async setDashboardConfig(slug: string, config: unknown): Promise<DashboardResponse> {
144
- return callDashboardApi('/adminapi/v1/dashboard/set_dashboard_config', { slug, config })
145
- },
146
-
147
143
  async addDashboardGroup(slug: string): Promise<DashboardResponse> {
148
144
  return callDashboardApi('/adminapi/v1/dashboard/add_dashboard_group', { slug })
149
145
  },