UNPKG

@adonis-agora/agent

Version:

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

52 lines • 3.66 kB
import type { HttpContext } from '@adonisjs/core/http'; import type { Actor } from './types.js'; /** * Authorization gate for the cross-actor `/agent/governance/*` read routes. It runs AFTER the actor * is resolved (so the caller is already authenticated), and decides whether THIS actor may read the * platform-wide governance read-model (every actor's spend/usage/threads/approvals). Return `false` * to deny (the route replies `403`). * * The gate is what makes those routes exist: omit it and the provider does NOT mount * `/agent/governance/*` at all (every route answers `404`). Set it to mount them gated, or set * `governanceAuthorize: () => true` to deliberately restore the old behaviour of letting ANY * authenticated actor read them. `GET /agent/approvals/mine` is unaffected — it stays mounted and * scoped to the calling actor's own pending approvals. * * Mirrors `@adonis-agora/agent-dashboard`'s `authorize` hook so the JSON routes and the console SPA * that reads them can be gated with the SAME predicate (typically "actor is ADMIN"). */ export type AgentGovernanceAuthorize = (actor: Actor, ctx: HttpContext) => boolean | Promise<boolean>; /** The decision {@link evaluateGovernanceGate} returns: proceed, or reply `status` with `error`. */ export interface GovernanceGateVerdict { ok: boolean; /** The HTTP status to reply when `!ok` (always `403` here — the caller is already authenticated). */ status: number; error?: string; } /** * Decide whether an already-resolved actor holds cross-actor governance privilege — the router-free * core of the provider's governance gate, extracted so it can be unit tested without booting an app. * * - No `authorize` configured → `{ ok: true }` (see the caveat below — the provider never gets here). * - `authorize` returns truthy → `{ ok: true }`. * - `authorize` returns falsy → `{ ok: false, status: 403 }`. * - `authorize` throws → `{ ok: false, status: 403 }` (fail-closed). `debug` decides whether the * thrown `.message` reaches the client (`true`, e.g. local dev — the message is meant for whoever * is wiring `governanceAuthorize`, useful to see while testing it) or a generic `'forbidden'` * (`false`, the default — this predicate runs on every request from a caller who is, by * definition, not yet proven trustworthy; matches `@adonis-agora/durable`'s dashboard convention of * a uniform message on every credential failure). The provider passes `!app.inProduction`. * * The `undefined` branch is a pure-function convenience, NOT a claim that governance is readable * without a gate. Neither provider caller can reach it: `#resolveGovernanceActor` backs the * `/agent/governance/*` routes, which are NOT mounted at all when no gate is configured (they answer * `404`), so it always passes one; and `#assertOwner` — which reuses this predicate as the "may act * across actors" seam for the per-actor run/thread routes — short-circuits to "not privileged" when * no gate is configured, leaving ownership strict, rather than calling in. To mount the governance * routes, set `governanceAuthorize` (typically an ADMIN check); to deliberately restore the old * behaviour of letting ANY authenticated actor read them, set `governanceAuthorize: () => true`. * Either way `GET /agent/approvals/mine` is unaffected — it stays mounted and scoped to the calling * actor's own pending approvals. */ export declare function evaluateGovernanceGate(actor: Actor, ctx: HttpContext, authorize?: AgentGovernanceAuthorize, debug?: boolean): Promise<GovernanceGateVerdict>; //# sourceMappingURL=governance-gate.d.ts.map