UNPKG

@adonis-agora/agent

Version:

Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.

119 lines • 7.16 kB
import type { HttpContext } from '@adonisjs/core/http'; import type { AgentGovernanceAuthorize } from '../governance-gate.js'; import type { Actor } from '../types.js'; import type { AccessDeniedOption as GenericAccessDeniedOption, AccessDeniedRenderer as GenericAccessDeniedRenderer } from './access_denied_page.js'; /** * The function form of {@link AgentDashboardConfig.accessDenied}: render (or answer) a refused * page navigation yourself. Receives the refusal ({@link AccessDeniedInfo}) and the AdonisJS * {@link HttpContext}. Return an HTML string to have it served; answer the request yourself (a * redirect, most commonly) and return nothing to make the provider stand down; return nothing * WITHOUT answering and the built-in page is served. */ export type AccessDeniedRenderer = GenericAccessDeniedRenderer<HttpContext>; /** `accessDenied` in either form — an options object for the built-in page, or a renderer. */ export type AccessDeniedOption = GenericAccessDeniedOption<HttpContext>; /** * An extra authorization gate for the dashboard, run AFTER the agent config's `actorResolver` has * resolved the caller. Return `false` (or throw) to deny — the request gets `403`. The governance * read-model the SPA serves spans EVERY actor's spend/usage, so most apps restrict the console beyond * mere authentication, e.g. `(actor) => actor.roles?.includes('ADMIN') ?? false`. */ export type AgentDashboardAuthorize = (actor: Actor, ctx: HttpContext) => boolean | Promise<boolean>; /** * Runs when the agent config's `actorResolver` itself rejects the caller — no resolver configured, or * `resolve(ctx)` threw (e.g. `AuthActorResolver` over an anonymous `ctx.auth`) — so there is no * resolved {@link Actor} to hand to {@link AgentDashboardAuthorize}. Deliberately ctx-only, never a * fabricated actor: the resolver's whole contract is "never invent an identity", and this hook must * not undermine that. * * Called BEFORE the gate writes its default `401 { error }` JSON. To show something other than that * JSON — a redirect to the app's own login page, most commonly — set a response header inside this * hook (typically via `ctx.response.redirect(...)`); the gate detects the `location` header and skips * its own write. Anything else (return normally without touching the response) falls through to the * default JSON, so this is safe to omit or to use only for side effects (e.g. logging). */ export type AgentDashboardUnauthenticatedHook = (ctx: HttpContext) => void | Promise<void>; /** * Optional `config('agent').dashboard` block. The dashboard reuses the agent config's `path` and * `actorResolver` (so it sits behind the SAME actor gating as the governance routes); this block * toggles it on/off, optionally overrides the mount path, and optionally adds an `authorize` gate. * * Shared by BOTH the embedded dashboard provider (`@adonis-agora/agent/dashboard_provider`, wired * automatically when you `node ace configure @adonis-agora/agent`) and the standalone * `@adonis-agora/agent-dashboard` package's provider — one config block controls whichever one is * registered. */ export interface AgentDashboardConfig { /** * Mount the SPA. Default `true` — set `false` to keep the routes off entirely. Note `true` is * necessary but not sufficient: the console also needs the agent's `governanceAuthorize` gate, see * {@link decideDashboardMount}. */ enabled?: boolean; /** Override the mount path. Default `<agentPath>/dashboard`. */ path?: string; /** * Extra authorization run after the actor resolves. Return `false` to deny (`403`). Omit to allow * any resolved actor (the default) — note this is only an EXTRA gate on the SPA shell; whether the * console mounts at all, and whether its data is readable, is decided by the agent config's * `governanceAuthorize`. */ authorize?: AgentDashboardAuthorize; /** * Runs when the actor resolver itself rejects the caller (no resolver, or `resolve(ctx)` threw) — * the one denial `authorize` never sees, since there is no resolved actor to hand it. Set a * response header inside (e.g. `ctx.response.redirect('/login')`) to replace the default * `401 { error }` JSON with a custom page/redirect. See {@link AgentDashboardUnauthenticatedHook}. */ onUnauthenticated?: AgentDashboardUnauthenticatedHook; /** * What a BROWSER sees when the gate refuses — the SPA shell or its assets (the console has no * JSON routes of its own; its data comes from the agent's `/agent/governance/*` routes, which are * unaffected). Omit it for the built-in page — a dark card in the console's own visual language * with the status, a sentence explaining the refusal and a "Back to app" link. Pass an object to * tweak that page (`brand`, `title`, `message`, `homeHref`, `accent`, …), or a function to * render/answer it yourself — see {@link AccessDeniedRenderer}. A redirect written by * `onUnauthenticated` or `authorize` still wins: the provider never overwrites a `location` header. */ accessDenied?: AccessDeniedOption; } export interface ResolvedAgentDashboardConfig { enabled: boolean; path?: string; authorize?: AgentDashboardAuthorize; onUnauthenticated?: AgentDashboardUnauthenticatedHook; accessDenied?: AccessDeniedOption; } /** Fill defaults for the optional dashboard config block. */ export declare function resolveDashboardConfig(config: AgentDashboardConfig | undefined): ResolvedAgentDashboardConfig; /** Whether the provider registers the console's routes, and (when it refuses) what to say about it. */ export type DashboardMountDecision = { mount: true; } | { mount: false; reason: 'disabled'; } | { mount: false; reason: 'no-governance-gate'; warning: string; } | { mount: false; reason: 'no-governance-queries'; warning: string; }; /** * Decide whether to register the console's routes at all — the router-free core of the provider's * mount check, extracted so it can be unit tested without booting an app. * * The console is a pure consumer of the agent's cross-actor `/agent/governance/*` read routes, and * those routes are not mounted unless the agent config carries a `governanceAuthorize` gate. Serving * a shell that can only 404 its own data is worse than not serving it: the failure shows up as seven * dead panels at click time with nothing anywhere explaining why. So the console follows the same * fail-closed-by-omission rule one layer down — no gate, no routes — and says so at boot. * * This costs nothing that still works: every app affected is an app whose console is ALREADY dead in * every view but Quota. `dashboard.authorize` is deliberately NOT the trigger; it gates the shell, * not the data, and an app can set it and still have a console with nothing to render. */ export declare function decideDashboardMount(enabled: boolean, governanceAuthorize: AgentGovernanceAuthorize | undefined, governanceQueries?: unknown): DashboardMountDecision; //# sourceMappingURL=define_config.d.ts.map