@adminforth/agent 1.1.0 → 1.2.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.
@@ -0,0 +1,209 @@
1
+ name: data-analytics
2
+ description: Analyze AdminForth resource data, summarize trends, and create charts from fetched rows.
3
+ ---
4
+
5
+ # Involved tools
6
+
7
+ Use `get_resource` first if you need to inspect resource structure and column names.
8
+
9
+ Use `get_resource_data` to fetch data for this skill. This is the main tool for loading rows for analytics, comparisons, distributions, and trend analysis.
10
+
11
+ # Instructions
12
+
13
+ When the user asks for analytics, reports, trends, comparisons, or distributions:
14
+
15
+ - Fetch the underlying rows with `get_resource_data`.
16
+ - Prefer narrow requests: request only the columns you need and use filters, sorting, pagination, and date ranges whenever possible.
17
+ - If the request is ambiguous, clarify the resource, metric, grouping, or date range before fetching data.
18
+ - Compute aggregates from the returned rows yourself: sums, counts, averages, min/max, grouped totals, ratios, and trend deltas.
19
+ - Return a short written summary with the key finding and most important numbers.
20
+ - If a chart would help, produce a Vega-Lite spec.
21
+
22
+ # Charts
23
+
24
+ Use Vega-Lite syntax for charts.
25
+
26
+ Return every chart as valid JSON inside a `vega-lite` fenced code block.
27
+
28
+ Every chart spec should include:
29
+ - `title.text`
30
+ - `title.subtitle`
31
+ - explicit axis titles when axes are used
32
+ - tooltips for the key fields
33
+
34
+ ### Line chart
35
+
36
+ ```vega-lite
37
+ {
38
+ "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
39
+ "title": {
40
+ "text": "Orders by Day",
41
+ "subtitle": "Daily order count for the selected date range"
42
+ },
43
+ "data": {
44
+ "values": [
45
+ { "date": "2026-04-01", "orders": 18 },
46
+ { "date": "2026-04-02", "orders": 25 },
47
+ { "date": "2026-04-03", "orders": 21 },
48
+ { "date": "2026-04-04", "orders": 29 }
49
+ ]
50
+ },
51
+ "mark": { "type": "line", "point": true },
52
+ "encoding": {
53
+ "x": { "field": "date", "type": "temporal", "title": "Date" },
54
+ "y": { "field": "orders", "type": "quantitative", "title": "Orders" },
55
+ "tooltip": [
56
+ { "field": "date", "type": "temporal", "title": "Date" },
57
+ { "field": "orders", "type": "quantitative", "title": "Orders" }
58
+ ]
59
+ }
60
+ }
61
+ ```
62
+
63
+ ### Bar chart
64
+
65
+ ```vega-lite
66
+ {
67
+ "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
68
+ "title": {
69
+ "text": "Revenue by Category",
70
+ "subtitle": "Top categories in the current filtered dataset"
71
+ },
72
+ "data": {
73
+ "values": [
74
+ { "category": "Hardware", "revenue": 42000 },
75
+ { "category": "Software", "revenue": 31500 },
76
+ { "category": "Services", "revenue": 22750 }
77
+ ]
78
+ },
79
+ "mark": "bar",
80
+ "encoding": {
81
+ "x": { "field": "category", "type": "nominal", "title": "Category", "sort": "-y" },
82
+ "y": { "field": "revenue", "type": "quantitative", "title": "Revenue" },
83
+ "tooltip": [
84
+ { "field": "category", "type": "nominal", "title": "Category" },
85
+ { "field": "revenue", "type": "quantitative", "title": "Revenue" }
86
+ ]
87
+ }
88
+ }
89
+ ```
90
+
91
+ ### Area chart
92
+
93
+ ```vega-lite
94
+ {
95
+ "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
96
+ "title": {
97
+ "text": "Monthly Signups",
98
+ "subtitle": "New users accumulated across the last six months"
99
+ },
100
+ "data": {
101
+ "values": [
102
+ { "month": "2025-11-01", "signups": 120 },
103
+ { "month": "2025-12-01", "signups": 155 },
104
+ { "month": "2026-01-01", "signups": 168 },
105
+ { "month": "2026-02-01", "signups": 190 },
106
+ { "month": "2026-03-01", "signups": 214 },
107
+ { "month": "2026-04-01", "signups": 238 }
108
+ ]
109
+ },
110
+ "mark": { "type": "area", "line": true, "point": true },
111
+ "encoding": {
112
+ "x": { "field": "month", "type": "temporal", "title": "Month" },
113
+ "y": { "field": "signups", "type": "quantitative", "title": "Signups" },
114
+ "tooltip": [
115
+ { "field": "month", "type": "temporal", "title": "Month" },
116
+ { "field": "signups", "type": "quantitative", "title": "Signups" }
117
+ ]
118
+ }
119
+ }
120
+ ```
121
+
122
+ ### Scatter plot
123
+
124
+ ```vega-lite
125
+ {
126
+ "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
127
+ "title": {
128
+ "text": "Ad Spend vs Revenue",
129
+ "subtitle": "Campaign-level correlation for the selected month"
130
+ },
131
+ "data": {
132
+ "values": [
133
+ { "campaign": "Search", "spend": 1200, "revenue": 5400 },
134
+ { "campaign": "Social", "spend": 900, "revenue": 3100 },
135
+ { "campaign": "Email", "spend": 350, "revenue": 2200 },
136
+ { "campaign": "Affiliates", "spend": 700, "revenue": 3600 }
137
+ ]
138
+ },
139
+ "mark": { "type": "point", "filled": true, "size": 120 },
140
+ "encoding": {
141
+ "x": { "field": "spend", "type": "quantitative", "title": "Ad Spend" },
142
+ "y": { "field": "revenue", "type": "quantitative", "title": "Revenue" },
143
+ "tooltip": [
144
+ { "field": "campaign", "type": "nominal", "title": "Campaign" },
145
+ { "field": "spend", "type": "quantitative", "title": "Ad Spend" },
146
+ { "field": "revenue", "type": "quantitative", "title": "Revenue" }
147
+ ]
148
+ }
149
+ }
150
+ ```
151
+
152
+ ### Pie chart
153
+
154
+ ```vega-lite
155
+ {
156
+ "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
157
+ "title": {
158
+ "text": "Tickets by Status",
159
+ "subtitle": "Share of tickets in each workflow state"
160
+ },
161
+ "data": {
162
+ "values": [
163
+ { "status": "Open", "count": 42 },
164
+ { "status": "In Progress", "count": 27 },
165
+ { "status": "Resolved", "count": 58 }
166
+ ]
167
+ },
168
+ "mark": { "type": "arc", "innerRadius": 40 },
169
+ "encoding": {
170
+ "theta": { "field": "count", "type": "quantitative", "title": "Tickets" },
171
+ "color": { "field": "status", "type": "nominal", "title": "Status" },
172
+ "tooltip": [
173
+ { "field": "status", "type": "nominal", "title": "Status" },
174
+ { "field": "count", "type": "quantitative", "title": "Tickets" }
175
+ ]
176
+ }
177
+ }
178
+ ```
179
+
180
+ ### Histogram
181
+
182
+ ```vega-lite
183
+ {
184
+ "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
185
+ "title": {
186
+ "text": "Order Value Distribution",
187
+ "subtitle": "Histogram of order totals in the filtered result set"
188
+ },
189
+ "data": {
190
+ "values": [
191
+ { "order_total": 24 },
192
+ { "order_total": 31 },
193
+ { "order_total": 39 },
194
+ { "order_total": 42 },
195
+ { "order_total": 63 },
196
+ { "order_total": 78 },
197
+ { "order_total": 95 }
198
+ ]
199
+ },
200
+ "mark": "bar",
201
+ "encoding": {
202
+ "x": { "bin": true, "field": "order_total", "type": "quantitative", "title": "Order Total" },
203
+ "y": { "aggregate": "count", "type": "quantitative", "title": "Count" },
204
+ "tooltip": [
205
+ { "aggregate": "count", "type": "quantitative", "title": "Count" }
206
+ ]
207
+ }
208
+ }
209
+ ```
@@ -120,6 +120,10 @@ export const useAgentStore = defineStore('agent', () => {
120
120
  });
121
121
  const blockCloseOfChat = ref(false);
122
122
 
123
+ function sortSessionsListByTimestamp(sessionsList: ISessionsListItem[]) {
124
+ return [...sessionsList].sort((a: ISessionsListItem, b: ISessionsListItem) => b.timestamp.localeCompare(a.timestamp));
125
+ }
126
+
123
127
  async function sendMessage() {
124
128
  const message = trimmedUserMessage.value;
125
129
  if (!message || isResponseInProgress.value) {
@@ -128,6 +132,11 @@ export const useAgentStore = defineStore('agent', () => {
128
132
  if (!currentSession.value || currentSession.value.sessionId === 'pre-session') {
129
133
  await createNewSession(message);
130
134
  }
135
+ currentSession.value.timestamp = new Date().toISOString();
136
+ sessionList.value = sortSessionsListByTimestamp(sessionList.value.map((s: ISessionsListItem) => s.sessionId === currentSession.value?.sessionId ? {
137
+ ...s,
138
+ timestamp: currentSession.value?.timestamp || s.timestamp,
139
+ } : s));
131
140
  lastMessage.value = message;
132
141
  currentChat.value?.sendMessage({
133
142
  text: message,
package/dist/index.js CHANGED
@@ -71,6 +71,14 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
71
71
  return { ok: true };
72
72
  });
73
73
  }
74
+ updateSessionDate(sessionId) {
75
+ return __awaiter(this, void 0, void 0, function* () {
76
+ yield this.adminforth.resource(this.options.sessionResource.resourceId).update(sessionId, {
77
+ [this.options.sessionResource.createdAtField]: new Date().toISOString(),
78
+ });
79
+ return { ok: true };
80
+ });
81
+ }
74
82
  getSessionTurns(sessionId) {
75
83
  return __awaiter(this, void 0, void 0, function* () {
76
84
  const turns = yield this.adminforth.resource(this.options.turnResource.resourceId).list([Filters.EQ(this.options.turnResource.sessionIdField, sessionId)], undefined, undefined, [Sorts.ASC(this.options.turnResource.createdAtField)]);
@@ -134,6 +142,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
134
142
  const userTimeZone = (_e = body.timeZone) !== null && _e !== void 0 ? _e : 'UTC';
135
143
  const sessionId = body.sessionId || (adminUser === null || adminUser === void 0 ? void 0 : adminUser.pk) || (adminUser === null || adminUser === void 0 ? void 0 : adminUser.username) || 'default';
136
144
  const turnId = yield this.createNewTurn(sessionId, prompt);
145
+ yield this.updateSessionDate(sessionId);
137
146
  let fullResponse = "";
138
147
  let isStreamClosed = false;
139
148
  const sequenceDebugCollector = createSequenceDebugCollector();
package/index.ts CHANGED
@@ -87,6 +87,13 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
87
87
  return {ok: true};
88
88
  }
89
89
 
90
+ private async updateSessionDate(sessionId: string) {
91
+ await this.adminforth.resource(this.options.sessionResource.resourceId).update(sessionId, {
92
+ [this.options.sessionResource.createdAtField]: new Date().toISOString(),
93
+ });
94
+ return {ok: true};
95
+ }
96
+
90
97
  private async getSessionTurns(sessionId: string) {
91
98
  const turns = await this.adminforth.resource(this.options.turnResource.resourceId).list(
92
99
  [Filters.EQ(this.options.turnResource.sessionIdField, sessionId)],
@@ -150,6 +157,7 @@ export default class AdminForthAgentPlugin extends AdminForthPlugin {
150
157
  const userTimeZone = (body.timeZone as string | undefined) ?? 'UTC';
151
158
  const sessionId = body.sessionId || adminUser?.pk || adminUser?.username || 'default';
152
159
  const turnId = await this.createNewTurn(sessionId, prompt);
160
+ await this.updateSessionDate(sessionId);
153
161
  let fullResponse = "";
154
162
  let isStreamClosed = false;
155
163
  const sequenceDebugCollector = createSequenceDebugCollector();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/agent",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",