@adonis-agora/agent-dashboard 0.7.1 → 0.7.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @adonis-agora/agent-dashboard
2
2
 
3
+ ## 0.7.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#82](https://github.com/DavideCarvalho/adonis-agora-agent/pull/82) [`59be4e9`](https://github.com/DavideCarvalho/adonis-agora-agent/commit/59be4e9943b47d79ce5f006c1d24b9b39e052f84) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Add TanStack Intent agent skills. Both packages now ship a `skills/` directory
8
+ (five skills under @adonis-agora/agent: setup, tools, governance, personas &
9
+ multi-agent delegation, offline testing; one under @adonis-agora/agent-dashboard:
10
+ the governance console client) that coding agents can load as structured,
11
+ verified documentation. The directories are included in each package's `files`
12
+ allowlist, and `@tanstack/intent` is added as a devDependency so CI can enforce
13
+ skill validity via `intent validate`.
14
+
3
15
  ## 0.7.1
4
16
 
5
17
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adonis-agora/agent-dashboard",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Read-only governance console (spend by model/actor, usage trend, recent threads & tool calls, quota) for @adonis-agora/agent — a dependency-light React SPA served by a thin AdonisJS provider. Part of the Agora ecosystem.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -32,7 +32,8 @@
32
32
  "files": [
33
33
  "dist/",
34
34
  "README.md",
35
- "CHANGELOG.md"
35
+ "CHANGELOG.md",
36
+ "skills"
36
37
  ],
37
38
  "sideEffects": false,
38
39
  "peerDependencies": {
@@ -46,6 +47,7 @@
46
47
  },
47
48
  "devDependencies": {
48
49
  "@adonisjs/core": "7.4.0",
50
+ "@tanstack/intent": "^0.3.2",
49
51
  "@testing-library/react": "16.3.2",
50
52
  "@types/node": "22.20.1",
51
53
  "@types/react": "19.2.18",
@@ -57,7 +59,7 @@
57
59
  "typescript": "5.9.3",
58
60
  "vite": "7.3.6",
59
61
  "vitest": "3.2.7",
60
- "@adonis-agora/agent": "0.24.0"
62
+ "@adonis-agora/agent": "0.25.3"
61
63
  },
62
64
  "engines": {
63
65
  "node": ">=20.6.0"
@@ -73,6 +75,7 @@
73
75
  "react",
74
76
  "spend",
75
77
  "usage",
78
+ "tanstack-intent",
76
79
  "agora"
77
80
  ],
78
81
  "scripts": {
@@ -0,0 +1,205 @@
1
+ ---
2
+ name: agent-console-client
3
+ description: >-
4
+ Serve and consume the @adonis-agora/agent governance console: the embedded provider
5
+ from node ace configure @adonis-agora/agent vs the standalone @adonis-agora/
6
+ agent-dashboard provider (register only ONE — duplicate-route error), the shared
7
+ config('agent').dashboard block { enabled, path, authorize, onUnauthenticated },
8
+ decideDashboardMount refusal reasons (no-governance-gate vs no-governance-queries),
9
+ and the framework-free AgentClient from @adonis-agora/agent-dashboard/client
10
+ (spendByModel/spendByActor/usageTrend/quotaToday/recentThreads/recentToolCalls/
11
+ pendingApprovals/approveToolCall) with window.__AGENT_DASHBOARD_BASE__ resolution.
12
+ Use for "dashboard blank or won't mount", "governance console 404", "build a custom
13
+ governance UI", "approve HITL calls from the browser".
14
+ metadata:
15
+ type: core
16
+ library: "@adonis-agora/agent-dashboard"
17
+ library_version: "0.7.1"
18
+ framework: adonisjs
19
+ sources:
20
+ - "DavideCarvalho/adonis-agent:packages/dashboard/README.md"
21
+ - "DavideCarvalho/adonis-agent:packages/dashboard/src/client/agent-client.ts"
22
+ - "DavideCarvalho/adonis-agent:packages/adonis/src/dashboard/define_config.ts"
23
+ - "DavideCarvalho/adonis-agent:packages/adonis/docs/governance/dashboard.mdx"
24
+ ---
25
+
26
+ # The governance console & browser client
27
+
28
+ `@adonis-agora/agent-dashboard` is a read-only React SPA over `@adonis-agora/agent`'s
29
+ cross-actor `/agent/governance/*` read routes — spend by model/actor, usage trend,
30
+ threads, tool calls, quota, and the HITL approvals inbox. Since agent@0.21.0 the same SPA
31
+ ships EMBEDDED in `@adonis-agora/agent`; this package remains for standalone installs and
32
+ for its framework-free browser client.
33
+
34
+ ## Setup
35
+
36
+ Most apps need nothing: `node ace configure @adonis-agora/agent` registers an embedded
37
+ provider that serves the SPA at `<path>/dashboard` once `governanceAuthorize` exists:
38
+
39
+ ```ts
40
+ // config/agent.ts — the gate is what makes the console mount at all.
41
+ import { defineConfig } from '@adonis-agora/agent'
42
+
43
+ export default defineConfig({
44
+ model: () => aiSdkModel(openai('gpt-4o-mini')),
45
+ store: 'lucid',
46
+ stores: { lucid: stores.lucid() },
47
+ actorResolver: new AuthActorResolver(),
48
+ governanceAuthorize: (actor) => actor.roles?.includes('ADMIN') ?? false,
49
+ // dashboard: { enabled: true, path: '/agent/dashboard', authorize: (actor) => actor.roles?.includes('ADMIN') ?? false },
50
+ })
51
+ ```
52
+
53
+ Standalone install (independent release cadence):
54
+
55
+ ```bash
56
+ pnpm add @adonis-agora/agent-dashboard
57
+ node ace add @adonis-agora/agent-dashboard
58
+ ```
59
+
60
+ ```ts
61
+ // adonisrc.ts — AFTER the agent provider; register only ONE of the two.
62
+ providers: [
63
+ () => import('@adonis-agora/agent/agent_provider'),
64
+ () => import('@adonis-agora/agent-dashboard'),
65
+ ]
66
+ ```
67
+
68
+ Both providers read the SAME `config('agent').dashboard` block, so switching between them
69
+ needs no config change.
70
+
71
+ Source: `packages/dashboard/README.md`, `packages/adonis/README.md` ("Dashboard").
72
+
73
+ ## Core patterns
74
+
75
+ ### Pattern 1 — drive the governance API with `AgentClient`
76
+
77
+ The framework-free fetch client mirrors the read surface plus pricing and HITL actions;
78
+ it sends `credentials: 'same-origin'`, so the host's session cookie gates every call
79
+ exactly as the routes do server-side:
80
+
81
+ ```ts
82
+ import { AgentClient } from '@adonis-agora/agent-dashboard/client'
83
+
84
+ const client = new AgentClient({ baseUrl: '/agent' })
85
+
86
+ const byModel = await client.spendByModel({ fromDay: '2026-03-01', toDay: '2026-03-07' })
87
+ const trend = await client.usageTrend({ fromDay: '2026-03-01', toDay: '2026-03-07' })
88
+ const quota = await client.quotaToday()
89
+ const approvals = await client.pendingApprovals({})
90
+
91
+ // HITL decisions from your own UI:
92
+ await client.approveToolCall(runId, toolCallId)
93
+ await client.rejectToolCall(runId, toolCallId, 'not this account')
94
+
95
+ // Pricing table maintenance:
96
+ await client.upsertPrice({ modelId: 'gpt-4o-mini', inputPricePer1m: 0.15, outputPricePer1m: 0.6 })
97
+ ```
98
+
99
+ Non-2xx responses throw `AgentApiError` carrying the HTTP status for branching.
100
+
101
+ Source: `packages/dashboard/src/client/agent-client.ts`, `packages/dashboard/src/client/index.ts`.
102
+
103
+ ### Pattern 2 — redirect to login via `onUnauthenticated`
104
+
105
+ The one denial `authorize` never sees is a failed actor resolution. Set a response header
106
+ inside the hook (typically a redirect); the gate detects it and skips its default
107
+ `401 { error }` JSON write:
108
+
109
+ ```ts
110
+ // config/agent.ts
111
+ export default defineConfig({
112
+ // ...
113
+ dashboard: {
114
+ onUnauthenticated: (ctx) => ctx.response.redirect('/login'),
115
+ },
116
+ })
117
+ ```
118
+
119
+ Return normally without touching the response and the default JSON is written instead —
120
+ the hook is safe to omit or use purely for logging.
121
+
122
+ Source: `packages/adonis/src/dashboard/define_config.ts`
123
+ (`AgentDashboardUnauthenticatedHook`).
124
+
125
+ ### Pattern 3 — diagnose a dead console from the boot warning
126
+
127
+ `decideDashboardMount(enabled, governanceAuthorize, governanceQueries)` produces three
128
+ distinct refusals, each logged with wording that names the responsible knob:
129
+
130
+ | Condition | Reason | Fix |
131
+ | --- | --- | --- |
132
+ | `enabled: false` | `disabled` | intentional; no warning |
133
+ | no `governanceAuthorize` | `no-governance-gate` | set the gate (or `() => true` deliberately) |
134
+ | `governanceQueries: false` | `no-governance-queries` | remove the `false` / wire a read-model |
135
+
136
+ The two non-disabled warnings are deliberately DIFFERENT strings so an operator staring
137
+ at a 404 can tell from the log alone which knob is responsible.
138
+
139
+ Source: `packages/adonis/src/dashboard/define_config.ts` (`decideDashboardMount`,
140
+ warning constants).
141
+
142
+ ## Common mistakes
143
+
144
+ ### HIGH — registering both dashboard providers
145
+
146
+ ```ts
147
+ // Wrong — embedded AND standalone serve <path>/dashboard.
148
+ providers: [
149
+ () => import('@adonis-agora/agent/agent_provider'),
150
+ () => import('@adonis-agora/agent/dashboard_provider'),
151
+ () => import('@adonis-agora/agent-dashboard'),
152
+ ]
153
+ ```
154
+
155
+ ```ts
156
+ // Correct — exactly one of the two.
157
+ providers: [
158
+ () => import('@adonis-agora/agent/agent_provider'), // its embedded dashboard_provider rides along
159
+ ]
160
+ ```
161
+
162
+ Mechanism: both mounts claim the same route path, so boot throws AdonisJS's duplicate
163
+ route error — the app fails to start rather than double-serving.
164
+ Source: `packages/dashboard/README.md` ("Register only ONE of the two providers"),
165
+ `packages/adonis/README.md`.
166
+
167
+ ### MEDIUM — setting only `dashboard.enabled: true` and expecting panels to load
168
+
169
+ ```ts
170
+ // Wrong — enabled is necessary but NOT sufficient; every panel but Quota reads gated routes.
171
+ dashboard: { enabled: true }
172
+ ```
173
+
174
+ ```ts
175
+ // Correct — the data gate is governanceAuthorize on the AGENT config.
176
+ governanceAuthorize: (actor) => actor.roles?.includes('ADMIN') ?? false,
177
+ dashboard: { enabled: true },
178
+ ```
179
+
180
+ Mechanism: without a gate the console refuses to mount entirely (boot warning naming the
181
+ knob) because it would otherwise load and fail on every panel — serving a shell that can
182
+ only 404 its own data is worse than not serving it.
183
+ Source: `packages/adonis/src/dashboard/define_config.ts` (`decideDashboardMount`,
184
+ `NO_GOVERNANCE_GATE_WARNING`).
185
+
186
+ ### LOW — hard-coding `/agent` as the client base in a custom UI
187
+
188
+ ```ts
189
+ // Wrong — breaks the moment the app mounts the agent under a prefix like /api/agent.
190
+ const client = new AgentClient({ baseUrl: '/agent' })
191
+ ```
192
+
193
+ ```ts
194
+ // Correct — reuse the same resolution the SPA uses: injected value wins, else derive.
195
+ import { resolveApiBase } from '@adonis-agora/agent-dashboard/client'
196
+ const client = new AgentClient({ baseUrl: resolveApiBase() })
197
+ ```
198
+
199
+ Mechanism: the provider injects the exact mounted base as `window.__AGENT_DASHBOARD_BASE__`
200
+ when serving index.html; absent that, `deriveApiBase(location.pathname)` strips the
201
+ trailing `/dashboard` segment — `/api/agent/dashboard` → `/api/agent`.
202
+ Source: `packages/dashboard/src/client/api-base.ts` (`resolveApiBase`, `deriveApiBase`).
203
+
204
+ See also: `agent-governance/SKILL.md` — the `governanceAuthorize` gate this console
205
+ consumes through; `agent-setup/SKILL.md` — seeding prices so `upsertPrice` rows matter.