UNPKG

@adonis-agora/agent

Version:

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

64 lines • 2.85 kB
/** Default {@link Actor} → authz subject mapping: the minimal `{ id }` authz needs to resolve a `SubjectRef`. */ export function defaultUserFromActor(actor) { return { id: actor.id }; } /** * A {@link RolesPolicy} (the agent's `ToolAuthorizer` seam) backed by `@adonis-agora/authz` * (AdonisJS Bouncer). For each tool it checks the actor against the tool's declared `ability` * via {@link AuthzServiceLike.can}, scoped to the actor's tenant. * * Security posture — FAIL-CLOSED: * - A tool that declares no `ability` is NEVER authorized (deny). Unlike the role-based default, * there is no ADMIN fallback: with authz selected, an un-annotated tool is simply not reachable. * - Any error thrown while resolving the decision denies. * * Tenant isolation: `actor.tenantRef` is passed as the authz **scope** (`{ tenantId }`), so a * permission granted in one tenant never authorizes a tool call made in another. When the actor has * no `tenantRef`, the check runs against the global scope (authz's default). * * The agent's double check — the offered-tools filter AND the invoke-time re-check inside * `ToolRegistry` — both run through this same `can(actor, tool)`, so offer and invoke stay * consistent. */ export class AuthzToolAuthorizer { #authz; #userFromActor; constructor(config) { this.#authz = config.authz; this.#userFromActor = config.userFromActor ?? defaultUserFromActor; } async can(actor, tool) { // Fail-closed: no declared ability → deny. There is no role fallback under authz. if (tool.ability === undefined) return false; try { // Pass the actor's tenant as the authz scope so the grant is tenant-isolated. Omit the option // entirely when there is no tenantRef (global scope) — honors `exactOptionalPropertyTypes`. const options = actor.tenantRef !== undefined ? { scope: { tenantId: actor.tenantRef } } : {}; return await this.#authz.can(this.#userFromActor(actor), tool.ability, options); } catch { // Fail-closed: any failure resolving the decision denies. return false; } } } /** * Factory for an {@link AuthzToolAuthorizer}. Wire it in `config/agent.ts` as the tool authorizer, * replacing the ADMIN-only `DefaultToolAuthorizer`: * * ```ts * import { defineConfig } from '@adonis-agora/agent' * import { authzToolAuthorizer } from '@adonis-agora/agent/authz' * import authz from '@adonis-agora/authz/services/main' * * export default defineConfig({ * model: () => aiSdkModel(openai('gpt-4o-mini')), * authorizer: authzToolAuthorizer({ authz }), * }) * ``` */ export function authzToolAuthorizer(config) { return new AuthzToolAuthorizer(config); } //# sourceMappingURL=authz-tool-authorizer.js.map